相信很多編程新手村的同學(xué)們都會(huì)有一個(gè)疑問(wèn):C 語(yǔ)言如何調(diào)用函數(shù)的呢?局部變量的作用域?yàn)槭裁磧H限于函數(shù)內(nèi)?這個(gè)調(diào)用不是指C 語(yǔ)言上的函數(shù)調(diào)用的語(yǔ)法,而是在內(nèi)存的視角下,函數(shù)的調(diào)用過(guò)程。本文將從C 語(yǔ)言調(diào)用實(shí)例,內(nèi)存視角,反匯編代碼來(lái)探討C 語(yǔ)言函數(shù)的調(diào)用過(guò)程,也可以說(shuō)是C 語(yǔ)言函數(shù)調(diào)用過(guò)程圖解。通過(guò)這個(gè)C 語(yǔ)言函數(shù)調(diào)用過(guò)程圖解,同學(xué)們將會(huì)知道,C 語(yǔ)言函數(shù)在調(diào)用時(shí),內(nèi)存空間是怎樣變化的。
要想理解這一個(gè)過(guò)程還好涉及到函數(shù)棧幀的概念。函數(shù)棧幀指的是,在調(diào)用函數(shù)時(shí),系統(tǒng)在??臻g中給函數(shù)所分配的一段連續(xù)空間。其中 ebp(棧幀基址指針)則是指明了當(dāng)前函數(shù)的棧幀基地址,對(duì)函數(shù)的資源(局部變量、實(shí)參等)的訪問(wèn),都要通過(guò) ebp+offset(偏移量)來(lái)進(jìn)行訪問(wèn)。而 esp 則是棧指針,指示當(dāng)前??臻g棧頂?shù)奈恢谩?/p>
以下代碼即是此次探討 C 語(yǔ)言函數(shù)調(diào)用過(guò)程的實(shí)例源碼:
intsubFunc(intabc) { intdef=0x9999; abc=0x8888; returnabc; } int_tmain() { subFunc(0x2222); return0; }
源碼很簡(jiǎn)單,在一個(gè)主函數(shù)中,調(diào)用一個(gè)帶參數(shù)的子函數(shù)。源碼使用 Visual Studio2010 進(jìn)行調(diào)試,并同時(shí)查看內(nèi)存窗口、反匯編窗口及變量窗口。
進(jìn)入調(diào)試模式,并將斷點(diǎn)定在調(diào)用子函數(shù) subFunc()處,然后運(yùn)行并觀察。
通過(guò)觀察窗口,可以知道,此時(shí)還是在執(zhí)行 main 函數(shù),而 ebp(棧幀基址指針)指向的是 0x0073fb64,esp=0x0073fa98。從反匯編代碼可以看到,在調(diào)用函數(shù)前,需要先將參數(shù)壓棧,也就是將實(shí)參存到了 0x0073fa94 處,然后再調(diào)用到子函數(shù)。
進(jìn)入到子函數(shù)時(shí),esp 已經(jīng)變成了 0x0073fa8c,而 0x0073fa90 處存放的是,子函數(shù)執(zhí)行完后返回到 main 函數(shù)中的地址。進(jìn)入到子函數(shù)后,先將 main 函數(shù)的 ebp 壓棧,然后將當(dāng)前棧頂指針的值賦值給 ebp 作為當(dāng)前子函數(shù)的 subFunc()的棧幀基址指針。此時(shí) esp 和 ebp 都變成了 0x0073fa8c。
緊接著,可以看到,esp 一下子被減去了 0x0cch,也就是說(shuō)棧空間一下子增長(zhǎng)了 0x0cch,并且這段空間全部被賦值為 0xcc。再往下看,可以看到子函數(shù)中的局部變量被分配在了 0x0073fa84 處(因?yàn)樽兞渴?32 位的,然后 CPU 卻是 64 位的,所以空了 32 位不作使用),也就是說(shuō),這一段被初始化為 0xcc 的棧空間是被用來(lái)給局部變量分配空間的。
接下來(lái)再看,在 main 函數(shù)傳遞了一個(gè)實(shí)參 0x2222 給子函數(shù) subFunc 中的形參 abc。在對(duì) abc 進(jìn)行讀寫(xiě)時(shí),其實(shí)就是在對(duì)前面實(shí)參所被存儲(chǔ)的空間進(jìn)行讀寫(xiě),也就是說(shuō)形參在作為參數(shù)也作為局部變量的同時(shí),它所被分配的內(nèi)存空間是在函數(shù)棧幀基址 ebp 之下。
而子函數(shù)被執(zhí)行完后,返回的過(guò)程則是一個(gè)與上面過(guò)程相逆的過(guò)程。將相應(yīng)的數(shù)據(jù)出棧,恢復(fù) ebp 等信息,釋放子函數(shù)的??臻g,返回到主函數(shù)。所以局部變量的作用域只是在函數(shù)中,當(dāng)函數(shù)被執(zhí)行完返回時(shí),函數(shù)的棧幀都被釋放了,局部變量等數(shù)據(jù)也就沒(méi)有了,不存在了,也就是說(shuō)局部變量的生命周期是與函數(shù)的生命周期等同的。
經(jīng)過(guò)以上的 C 語(yǔ)言函數(shù)調(diào)用過(guò)程圖解,相信已經(jīng)理解了 C 語(yǔ)言在內(nèi)存中是如何調(diào)用的了。然后可以總結(jié)并得出下面的函數(shù)調(diào)用的棧幀圖解。從函數(shù)調(diào)用的層面看,棧空間是被從下往上一塊一塊地增長(zhǎng)的,并且是后分配的先被釋放,先分配的后被釋放。
編輯:hfy
-
內(nèi)存
+關(guān)注
關(guān)注
8文章
3019瀏覽量
74003 -
C語(yǔ)言
+關(guān)注
關(guān)注
180文章
7604瀏覽量
136688
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論