首先我們給出內存布局
|
高內存地址 |
棧 |
向下增長,可讀可寫可執行 |
空洞 |
向上增長 |
堆 |
向上增長,可讀可寫可執行 |
BSS段(未初始化數據段) |
向上增長,可讀可寫不可執行 |
.data 數據段 |
向上增長,可讀可寫不可執行 |
.text 文本段(代碼段) |
向上增長,可讀可寫不可執行 |
|
低內存地址 |
不同類型的變量在內存中的位置:
1,局部變量、函數參數存放在棧上。靜態局部變量,並不是在調用函數時分配,在函數返回時釋放,而是像全局變量一樣靜態分配在.data數據段,但它的作用域只在函數中起作用。
2,堆,給動態分配內存使用。
3,全局變量、靜態變量位於.data數據段;未初始化變量則位於.bss未初始化數據段。
4,const修飾的全局變量在.rodata只讀數據段(const變量在定義時必須初始化,如果未初始化將被設為0或空),只讀數據段在和.text同一個segment
5,代碼段即存儲程序文本。指令指針中的指令就從這里取得。這個段一般是可以被共享的:你可以使用兩個編輯器(vi?)來編輯文本,則它們共享一個代碼段。
全局變量初始化和未初始化的區別
我們都知道未初始化的靜態變量或全局變量將被初始化為空串或0;未初始化的局部變量的值不確定。
全局變量不初始化,則默認為0,存放在.bss數據段中。如int x = 0和int x效果一樣的。但是還是有差別的:
編譯器在編譯的時候針對這兩種情況會產生兩種符號放在目標文件的符號表中,對於初始化的,叫強符號,未初始化的,叫弱符號。
連接器在連接目標文件的時候,如果遇到兩個重名符號,會有以下處理規則:
1、如果有多個重名的強符號,則報錯。
2、如果有一個強符號,多個弱符號,則以強符號為准。
3、如果沒有強符號,但有多個重名的弱符號,則任選一個弱符號。
基於以上規則,使用以下程序測試
1 #include <stdio.h> 2 3 int global_int; 4 void setInt(); 5 6 int main() 7 { 8 printf(“未初始化全局變量: %d\n”, global_int); 9 setInt(); 10 printf(“改變全局變量: %d\n”, global_int); 11 } 12 13 int global_int; 14 15 void setInt() 16 { 17 global_int = 2; 18 }
以上程序正常運行。如果將第2行和第12行的global_int任意一個初始化,程序也正常運行。但將第2行和第12行的gloal_int都初始化,將會出現:error: redefinition of ‘global_int’;
所以我們盡量初始化全局變量。
除了連接有區別外,它們存儲的位置也不一樣:初始化的全局變量被保存在data數據段中;而未初始化的全局變量被保存在.bss數據段中。