淺談C語言的資料存放區

來源:互聯網
上載者:User

程式由指令和資料群組成,C語言程式亦是如此。開發人員在編寫程式的時候往往需要根據不同資料的特點以及程式需求來選擇不同的資料存放區方式,那麼在C語言中資料的儲存分為哪些方式呢?

C程式大致來講可以分為四個資料區:常量區,靜態去,堆區,棧區。

其中常量區儲存了未被作為初始化使用的字串常量和被const修飾的全域變數,其特點是只可被訪問不可被寫入,生命週期同程式的運行過程。

靜態區儲存了全部的全域變數,和所有被static修飾的變數(包括全域和局部),其特點是生命週期很長(為一次程式的運行過程)並且只被初始化一次(在編譯之後就已完成)。

棧區儲存了所有自動儲存(不加任何儲存類型關鍵字修飾或被auto修飾)的局部變數,其特點是生命週期很短,僅僅是該變數所在函數的一次調用過程。運行時有作業系統分配並在函數結束後回收。

堆區是由作業系統負責維護的大片記憶體池,使用時需手動申請(調用malloc家族函數),但使用完畢後需手動釋放,否則會造成嚴重的記憶體流失,直到該進程退出後才會被作業系統回收。

下面詳細介紹每種儲存類型的特點。

一.常量區:

故名思意,常量區裡存放的是一些不可改變的量,比如字串常量。在實際的ELF(Executable and Linkable Format,可執行串連格式,是UNIX系統實驗室(USL)作為應用程式二進位介面(Application Binary Interface,ABI)而開發和發布的。Linux 作為類unix系統其程式仍然沿用了該格式。)的程式資料是分段儲存的,對應的常量區就是“.rodata(唯讀資料)段“。

常量區的資料被標記為唯讀,也就是程式只有訪問權而沒有寫入權,因此如果開發人員需要使用某些不希望被改變的資料時可以將其放入常量區。

在C語言中常量有很多種,比如常見的:

字元常量:‘a’, ’A’, ’*’。

字串常量:”helloworld”,”ilovechina”,”12345”。

整常量: 25,10,012,0x0a,0b00001010。

浮點常量: 3.14,123.456, 3.0E-23;

但是並不是所有的常量都會被編譯器放在常量區的,1-1中代碼所示:

圖1-1 定義一個變數並被常量初始化

圖中程式定義了一個整型局部變數i,並且被初始化為10,其中i是變數,10是常量,但是編譯器並不將10放入常量區,而是在指令中直接通過立即數賦值(圖1-2)。

圖1-2 由圖1-1程式編譯產生的彙編代碼

這是因為編譯器認為普通的整型、浮點型或字元型常量在使用的時候是可以通過立即數來實現的,沒有必要額外儲存到資料區,如此節省了儲存空間和運行時的訪問時間。那麼什麼樣的資料才將放入常量區呢?

1.字串常量

1-1所示,在C程式中定義了一個局部的字元指標變數p指向一個字串常量,其中p由於是局部變數被放在棧區,而字串常量“helloworld”在彙編中被放入.rodata段(圖1-2),在編譯後產生的ELF格式檔案中也將被放入.rodata段(圖1-3)

圖1-3 C語言的樣本程式定義指標變數指向字串常量。

圖1-4 由圖1-3中代碼產生的組譯工具。

圖1-5 由圖1-3中程式編譯產生的可執行程式分析。

但是,當一個字元常量串被用來為數組初始化的時候,那麼該字串常量將不會放入常量區,而是放入對應的數組中,1-6所示:

圖1-6 定義一個字元數組並用字串常量初始化

編譯器會將該字串按照四位元組為一群組轉換成對應的32位整數來為該數組進行初始化,1-7所示,其中第13行的10進位整數1819043176轉換成16進位為0x6c6c6568,正好是字元‘l’,’l’,’e’,’h’:

圖1-7 圖1-6中C代碼產生的組譯工具

因此在編譯產生的ELF格式檔案中的.rodata段也將不會儲存該字串常量:

圖1-8 圖1-6程式編譯後產生的可執行程式片段。

2.被const修飾的全域變數

a)

除了字串之外,其他常量也可以放在常量區,但是前提是該資料必須被存放在全域變數的空間裡,並且被const關鍵字修飾。1-9代 碼所示:

圖1-9 第4行定義了一個被const修飾的全域變數

編譯產生的組譯工具比較:

其中value0由於被const修飾所以放在了.rodata段也就是所謂的常量區,而value1是一個普通的全域變數所以放在了.data段也就是所謂的待用資料區。分析編譯產生的ELF格式可執行程式如下:

圖1-11 value0的存放位置

其中value0的資料被放在常量區(.rodata段)十六進位顯示的0a對應了它的十進位初始值10。

圖1-12 value1的存放位置

Value1的資料被放在靜態區(.data段)十六進位顯示的14對應了它的十進位初始值20。

b)

但是並不是所有被const修飾過的變數都放在常量區,事實上只有全域變數才是如此,普通的局部變數被const修飾後僅僅意味著在運算式上不能顯式地改變該變數值,否則編譯器會報語法錯誤,但該變數仍存放在棧區。而由於其儲存地區沒有發生本質的改變,因此仍然可以通過其他方式改變其值,比如指標。1-13所示:

圖1-13 定義兩個局部變數,其中一個被const修飾

儲存,編譯,結果如下:

圖1-14 編譯器發生編譯錯誤

由於 value1被const修飾,所以程式第9行的指派陳述式將發生錯誤。

接著修改程式,通過指標去修改value1的值:

圖1-15 定義指標p指向value1並通過指標賦值。

編譯,運行:

圖1-16 編譯運行結果

由於定義的指標變數p和運算式&value1的類型不符(p是int *,而&value1的類型是const int *)所以在第7行賦值的時候編譯器會產生一個類型不符的警告,我們忽略該警告繼續運行,結果改變了value1的值。

3.由常量區引發的段錯誤

由於常量區的特性是唯讀,因此當程式試圖去向指向常量區的地址寫入資料的時候,作業系統處於安全考慮會發出一個段錯誤的訊號並且殺死該進程,以達到保護作業系統的目的。

圖1-17 範例程式碼,通過指標去向常量區寫資料。

第10行和11行的均可產生同樣的段錯誤,1-18所示

圖1-18 非法寫入引發的段錯誤

二.靜態區:

靜態區是一個抽象籠統的概念,在實際的Linux/C的可執行程式中並沒有靜態區這個地區,具體來講它主要由兩個段組成:.data段和.bss段。其中.data段就是程式的資料區段,在採用段式記憶體管理的架構中,資料區段(data segment)通常是指用來存放程式中已初始化且不為0的全域變數或靜態變數的一塊記憶體地區。相反,BSS(Block Started by Symbol)通常是指用來存放程式中未初始化的或初始化為0的全域變數或靜態變數的一塊記憶體地區。.data段在程式編譯期間其大小及資料被確定,而.bss段則沒有直接分配空間而是由編譯器在.data段之後為其預留空間,在程式裝載進記憶體時被正式分配。儘管靜態區由兩個不同的段組成,但是在程式連結並裝載進記憶體之後這兩段不做區分,因此我們在這裡不做分開討論。

靜態區的變數擁有以下特徵:

3) 生命週期長,直到該進程結束隨進程空間一起被系統回收。

4) 只初始化一次,它的空間資料在編譯期間被初始化,邏輯地址在連結期間固定。

那麼哪些變數將被放在靜態區呢?

3.全域變數:

顧名思義它是全域的公用的,如果一個變數被定義為全域的,那麼在同一個程式中,任何函數都可以去訪問、存取該變數的資料。基於此,全域變數除擁有靜態區變數的全部特徵之外還具有範圍廣的特點,其範圍在整個程式中(可以由多個源檔案組成)全域可見。

4.靜態變數

從字面上理解所謂靜態變數就是被static關鍵字修飾的變數,只要被static修飾為靜態變數那麼都將被編譯器分配在靜態區,其也就擁有了靜態區變數的全部特徵。靜態變數分兩種:全域靜態變數和局部靜態變數。無論哪種只要被static修飾都將放在靜態區,擁有靜態區變數的全部特徵。其區別僅在於範圍:如果是全域靜態變數,那麼該變數的範圍被限定只能在本源檔案內使用(編譯之後該變數的符號將不允許對外連結,但是仍然可以通過指標去間接訪問);如果是局部變數則沒有變化(僅限函數內部使用)。

下面給出一段範例程式碼用以說明靜態變數的特性(圖2-1):

圖 2-1

代碼中定義了一個全域變數gvalue和局部變數lvalue,並且經過兩次函數調用。gvalue由於是全域變數被編譯器分配在靜態區,而lvalue是局部變數放在棧區。由於靜態區的特寫導致gvalue經過兩次函數調用實現了累加,而局部變數lvalue則每次在函數調用時都被重新初始化。地址(圖2-2)。

圖 2-2

下面更改程式,將局部變數修改為靜態局部變數(圖2-3):

圖 2-3

則由於局部變數lvalue被static修飾放在了靜態區只初始化一次,因此也實現了累加(圖2-4)。

圖 2-4

原文出處:

淺談C語言的資料存放區(一):http://www.embedu.org/Column/Column540.htm

淺談C語言的資料存放區(二) :http://www.embedu.org/Column/Column558.htm

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.