轉自:https://blog.csdn.net/weixin_33724659/article/details/88028054
為了說明這個問題,咱們簡單的來說一下C里面變量在內存里面的存儲:
1.棧區(stack)— 由編譯器自動分配釋放 ,存放為運行函數而分配的局部變量、函數參數、返回數據、返回地址等。
2.堆區(heap) — 一般由程序員分配釋放, 用來存儲數組,結構體,對象等。若程序員不釋放,程序結束時可能由OS回收。
3.全局區(靜態區)(static)— 存放全局變量、靜態數據、常量。程序結束后由系統釋放。
4.文字常量區 — 常量字符串就是放在這里的。 程序結束后由系統釋放。
5.程序代碼區 — 存放函數體(類成員函數和全局函數)的二進制代碼。
棧內存是有大小限制的,比如默認情況下,Linux平台的是8MB,如果超過這個限制,就會出現 stackoverflow,而堆內存並無限制,內存有多大就可以申請多大。
看完上面的說明,我們可以得出一個結論: 全局變量存放在全局區,在程序一開始就分配好了,而且局部變量在存放在棧區,運行的時候分配內存,用完之后內存會被自動釋放。
但是這好像並沒有說明變量名在哪里吧?比如下面這段C代碼,a, b到底存在哪里?:
1 #include <stdio.h> 2 3 int a = 1; //全局初始化區 4 5 int main(int argc, char const *argv[]) 6 { 7 int b; //棧 8 b = a + 5; 9 printf("%d\n", b); 10 return 0; 11 }
為了搞明白這個問題,我們需要了解一下C語言的執行過程,C語言執行需要經過預處理(Preprocessing)、編譯(Compilation)、匯編(Assemble)、鏈接(Linking)等幾個階段,在編譯成匯編語言這個階段就已經沒有變量名了,使用gdb可以查看編譯后的匯編代碼:
(gdb) disass main Dump of assembler code for function main: 0x0000000000400526 <+0>: push %rbp 0x0000000000400527 <+1>: mov %rsp,%rbp 0x000000000040052a <+4>: sub $0x20,%rsp 0x000000000040052e <+8>: mov %edi,-0x14(%rbp) 0x0000000000400531 <+11>: mov %rsi,-0x20(%rbp) 0x0000000000400535 <+15>: mov 0x200afd(%rip),%eax # 0x601038 <a> 0x000000000040053b <+21>: add $0x5,%eax 0x000000000040053e <+24>: mov %eax,-0x4(%rbp) 0x0000000000400541 <+27>: mov -0x4(%rbp),%eax 0x0000000000400544 <+30>: mov %eax,%esi 0x0000000000400546 <+32>: mov $0x4005e4,%edi 0x000000000040054b <+37>: mov $0x0,%eax 0x0000000000400550 <+42>: callq 0x400400 <printf@plt> => 0x0000000000400555 <+47>: mov $0x0,%eax 0x000000000040055a <+52>: leaveq 0x000000000040055b <+53>: retq End of assembler dump.
雖然上面這個很難讀懂,但是應該能看到在這一大堆匯編指令執行的背后,並沒有變量名這個東西,所有的變量名到最后都變成了內存地址,匯編指令操作的是各種寄存器和內存地址。
定義int a;時,編譯器分配4個字節內存,並命名該4個字節的空間名字為a(即變量名),當用到變量名a時,就是在使用那4個字節的內存空間。 5是一個常數,在程序編譯時存放在代碼的常量區存放着它的值(就是5),當執行a=5時,程序將5這個常量拷貝到a所在的4個字節空間中,就完成了賦值操作.a是我們對那個整形變量的4個字節取的"名字",是我們人為給的,實際上計算機並不存儲a這個名字,只是我們編程時給那4個字節內存取個名字好用。實際上程序在編譯時,所有的a都轉換為了那個地址空間了,編譯成機器代碼后,沒有a這個說法了。a這個名字只存在於我們編寫的代碼中.5不是被隨機分配的,而總是位於程序的數據段中,可能在不同的機器上在數據段中的位置可能不一致,它的地址其實不能以我們常用到的內存地址來理解,因為牽扯到一個叫"計算機尋址方式"的問題。
以上的內容有參考網上很多文章,僅供參考!有一點需要明白在操作系統里面,程序的內存地址並不是物理地址,而且通過一個基址+偏移量的方式的計算得到的虛擬地址,操作系統為了更好的管理應用在內存這個層面做了很多抽象。