C語言里面變量和變量名的存儲(轉)


轉自: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不是被隨機分配的,而總是位於程序的數據段中,可能在不同的機器上在數據段中的位置可能不一致,它的地址其實不能以我們常用到的內存地址來理解,因為牽扯到一個叫"計算機尋址方式"的問題。

以上的內容有參考網上很多文章,僅供參考!有一點需要明白在操作系統里面,程序的內存地址並不是物理地址,而且通過一個基址+偏移量的方式的計算得到的虛擬地址,操作系統為了更好的管理應用在內存這個層面做了很多抽象。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM