C語言函數調用過程圖解——內存視角


TOMORROW 星辰 , 版權所有丨原文鏈接:C 語言函數調用過程圖解——內存視角

 

相信很多編程新手村的同學們都會有一個疑問:C 語言如何調用函數的呢?局部變量的作用域為什么僅限於函數內?這個調用不是指 C 語言上的函數調用的語法,而是在內存的視角下,函數的調用過程。本文將從 C 語言調用實例,內存視角,反匯編代碼來探討 C 語言函數的調用過程,也可以說是C 語言函數調用過程圖解。通過這個C 語言函數調用過程圖解,同學們將會知道,C 語言函數在調用時,內存空間是怎樣變化的。

要想理解這一個過程還好涉及到函數棧幀的概念。函數棧幀指的是,在調用函數時,系統在棧空間中給函數所分配的一段連續空間。其中 ebp(棧幀基址指針)則是指明了當前函數的棧幀基地址,對函數的資源(局部變量、實參等)的訪問,都要通過 ebp+offset(偏移量)來進行訪問。而 esp 則是棧指針,指示當前棧空間棧頂的位置。

以下代碼即是此次探討 C 語言函數調用過程的實例源碼:

int subFunc(int abc) {         int def=0x9999;         abc=0x8888;         return abc; }   int _tmain() {           subFunc(0x2222);                 return 0; }

 

源碼很簡單,在一個主函數中,調用一個帶參數的子函數。源碼使用 Visual Studio2010 進行調試,並同時查看內存窗口、反匯編窗口及變量窗口。

進入調試模式,並將斷點定在調用子函數 subFunc()處,然后運行並觀察。

通過觀察窗口,可以知道,此時還是在執行 main 函數,而 ebp(棧幀基址指針)指向的是 0x0073fb64,esp=0x0073fa98。從反匯編代碼可以看到,在調用函數前,需要先將參數壓棧,也就是將實參存到了 0x0073fa94 處,然后再調用到子函數。

C 語言函數調用過程圖解——內存視角

進入到子函數時,esp 已經變成了 0x0073fa8c,而 0x0073fa90 處存放的是,子函數執行完后返回到 main 函數中的地址。進入到子函數后,先將 main 函數的 ebp 壓棧,然后將當前棧頂指針的值賦值給 ebp 作為當前子函數的 subFunc()的棧幀基址指針。此時 esp 和 ebp 都變成了 0x0073fa8c。

C 語言函數調用過程圖解——內存視角

緊接着,可以看到,esp 一下子被減去了 0x0cch,也就是說棧空間一下子增長了 0x0cch,並且這段空間全部被賦值為 0xcc。再往下看,可以看到子函數中的局部變量被分配在了 0x0073fa84 處(因為變量是 32 位的,然后 CPU 卻是 64 位的,所以空了 32 位不作使用),也就是說,這一段被初始化為 0xcc 的棧空間是被用來給局部變量分配空間的。

C 語言函數調用過程圖解——內存視角

接下來再看,在 main 函數傳遞了一個實參 0x2222 給子函數 subFunc 中的形參 abc。在對 abc 進行讀寫時,其實就是在對前面實參所被存儲的空間進行讀寫,也就是說形參在作為參數也作為局部變量的同時,它所被分配的內存空間是在函數棧幀基址 ebp 之下。

C 語言函數調用過程圖解——內存視角

C 語言函數調用過程圖解——內存視角

而子函數被執行完后,返回的過程則是一個與上面過程相逆的過程。將相應的數據出棧,恢復 ebp 等信息,釋放子函數的棧空間,返回到主函數。所以局部變量的作用域只是在函數中,當函數被執行完返回時,函數的棧幀都被釋放了,局部變量等數據也就沒有了,不存在了,也就是說局部變量的生命周期是與函數的生命周期等同的。

經過以上的 C 語言函數調用過程圖解,相信已經理解了 C 語言在內存中是如何調用的了。然后可以總結並得出下面的函數調用的棧幀圖解。從函數調用的層面看,棧空間是被從下往上一塊一塊地增長的,並且是后分配的先被釋放,先分配的后被釋放。

 

C 語言函數調用過程圖解——內存視角

 

 

 


TOMORROW 星辰 , 版權所有丨如未注明 , 均為原創丨本網站采用 BY-NC-SA協議進行授權 
轉載請注明原文鏈接: C 語言函數調用過程圖解——內存視角
喜歡 (2)


免責聲明!

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



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