最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C語言函數(shù)棧幀的創(chuàng)建和銷毀詳解

 更新時間:2022年02月15日 17:17:56   作者:朱澤博  
這篇文章主要為大家詳細(xì)介紹了C語言函數(shù)棧幀的創(chuàng)建和銷毀,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助

寫在前面

我們知道,每一次函數(shù)調(diào)用都需要在棧區(qū)上為其開辟一塊空間,這塊空間就叫做這個函數(shù)的棧幀。

而棧是從高地址向低地址延伸的。每個函數(shù)的每次調(diào)用,都有它自己獨立的一個棧幀,這個棧幀中維持著所需要的各種信息。寄存器ebp指向當(dāng)前的棧幀的底部(高地址),寄存器esp指向當(dāng)前的棧幀的頂部(低地址)。

這樣我們就了解了寄存器ebp和寄存器esp中存放的是地址,這兩個地址是用來維護(hù)函數(shù)棧幀的。比如:調(diào)用main函數(shù), 我們?yōu)閙ain函數(shù)分配棧幀空間, 那么棧幀維護(hù)如下:

在這里插入圖片描述

下面我們通過一段代碼分析一下,函數(shù)棧幀創(chuàng)建和銷毀的過程:(棧幀這部分內(nèi)容在不同的編譯器上實現(xiàn)存在差異, 但是思想大致都是一致的。本文是在vs2013編譯器下實現(xiàn)的。)

#include <stdio.h>
int Add(int x, int y)
{
	int z = 0;
	z = x + y;
	return z;
}
int main(void)
{
	int a = 10;
	int b = 20;
	int ret = 0;
	ret = Add(a, b);//計算a+b
	printf("%d\n", ret);
	return 0;
}

我們在調(diào)試過程打開調(diào)用堆棧

在這里插入圖片描述

可以看出,main函數(shù)是在__tmainCRTStartup函數(shù)內(nèi)部被調(diào)用的,而__tmainCRTStartup函數(shù)又是在mainCRTStartup函數(shù)內(nèi)部調(diào)用的。

為了能更加清楚的看到棧幀創(chuàng)建和銷毀的過程,我們轉(zhuǎn)到上面代碼對應(yīng)的反匯編代碼:

int main(void)
{
009D3F40  push        ebp  //將edp壓入棧幀
009D3F41  mov         ebp,esp  //將esp的值賦給edp
009D3F43  sub         esp,0E4h  //esp-0E4h
009D3F49  push        ebx  
009D3F4A  push        esi  
009D3F4B  push        edi  
009D3F4C  lea         edi,[ebp+FFFFFF1Ch]  
009D3F52  mov         ecx,39h  
009D3F57  mov         eax,0CCCCCCCCh  
009D3F5C  rep stos    dword ptr es:[edi]  
	int a = 10;
009D3F5E  mov         dword ptr [ebp-8],0Ah  
	int b = 20;
009D3F65  mov         dword ptr [ebp-14h],14h  
	int ret = 0;
009D3F6C  mov         dword ptr [ebp-20h],0  
	ret = Add(a, b);//計算a+b
009D3F73  mov         eax,dword ptr [ebp-14h]  
009D3F76  push        eax  
009D3F77  mov         ecx,dword ptr [ebp-8]  
009D3F7A  push        ecx  
009D3F7B  call        009D11F9  
009D3F80  add         esp,8  
009D3F83  mov         dword ptr [ebp-20h],eax  
	printf("%d\n", ret);
009D3F86  mov         esi,esp  
009D3F88  mov         eax,dword ptr [ebp-20h]  
009D3F8B  push        eax  
009D3F8C  push        9D5860h  
009D3F91  call        dword ptr ds:[009D9118h]  
009D3F97  add         esp,8  
009D3F9A  cmp         esi,esp  
009D3F9C  call        009D1140  
	return 0;
009D3FA1  xor         eax,eax  
}
009D3FA3  pop         edi  
009D3FA4  pop         esi  
009D3FA5  pop         ebx  
009D3FA6  add         esp,0E4h  
009D3FAC  cmp         ebp,esp  
009D3FAE  call        009D1140  
009D3FB3  mov         esp,ebp  
009D3FB5  pop         ebp  
009D3FB6  ret  

main函數(shù)的調(diào)用 main函數(shù)棧幀的創(chuàng)建

經(jīng)過剛才我們的理解,在準(zhǔn)備調(diào)用main函數(shù)的時候,調(diào)用main函數(shù)的那個函數(shù)的棧幀已經(jīng)開辟好了。

在這里插入圖片描述

然后將ebp壓入棧幀,保存了指向棧底的ebp的地址,而此時esp指向新的棧頂位置;接著將esp的值賦給了ebp,產(chǎn)生了新的ebp;用esp減去一個16進(jìn)制數(shù)0E4H(這里就是為main函數(shù)預(yù)開辟空間)。緊接著三個壓棧指令,分別將ebx,esi,edi,壓入棧幀。加載完有效地址以后,將為main函數(shù)預(yù)開辟空間全部初始化為0xCCCCCCCC。最后創(chuàng)建了三個局部變量a,b,ret并進(jìn)行了初始化。

Add函數(shù)的調(diào)用

函數(shù)傳參

在這里插入圖片描述

將b的值存入寄存器eax中,再將eax壓入棧中;將a的值存入寄存器ecx中,再將將ecx壓入棧中;這里看出參數(shù)是從右向左傳遞的。緊接著執(zhí)行call指令,這里就是調(diào)用Add函數(shù),同時將call指令的下一條指令的地址壓入棧中,然后執(zhí)行call指令的時候按F11 , 就進(jìn)入了Add函數(shù)內(nèi)部。

Add函數(shù)棧幀的創(chuàng)建

在這里插入圖片描述

首先將main()函數(shù)的ebp壓入棧,保存指向main()函數(shù)棧幀底部的ebp的地址,此時esp指向新的棧頂位置;將esp的值賦給ebp,產(chǎn)生新的ebp,即Add()函數(shù)棧幀的ebp;給esp減去一個16進(jìn)制數(shù)0E4H,這里是為Add()函數(shù)預(yù)開辟空間;緊接著三個壓棧指令,分別將ebx,esi,edi,壓入棧幀。加載完有效地址以后,將為Add函數(shù)預(yù)開辟空間全部初始化0xCCCCCCCC。在緊接著創(chuàng)建了變量z,將形參的a和b相加的結(jié)果存儲到z中;最后將結(jié)果存儲到eax寄存器中,通過寄存器帶回了函數(shù)的返回值。

Add函數(shù)棧幀的銷毀

在這里插入圖片描述

edi、esi、ebx依次出棧,esp 會向下移動;然后將ebp的值賦給esp,使esp指向ebp指向的地方;接著ebp 出棧,同時將出棧的內(nèi)容給ebp,此時ebp又指向了main函數(shù)棧幀的底部,最后執(zhí)行ret 指令,表示出棧一次,并跳轉(zhuǎn)到出棧的內(nèi)容的地址處,也就是call指令的下一條指令處。

main函數(shù)棧幀的銷毀

在這里插入圖片描述

main函數(shù)棧幀的銷毀和Add函數(shù)棧幀銷毀的過程的思想都是一樣的,這里就不做多贅述了。

總結(jié)

通過上面的例子,我們知道了局部變量是如何創(chuàng)建的,知道了為什么創(chuàng)建局部變量不初始化,會導(dǎo)致里面的內(nèi)容是隨機值;對函數(shù)是如何傳參的,以及傳參順序是如何也有了較為深入的了解。

本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!       

相關(guān)文章

  • 利用C++單例模式實現(xiàn)高性能配置管理器

    利用C++單例模式實現(xiàn)高性能配置管理器

    這篇文章主要為大家詳細(xì)介紹了如何利用C++單例模式實現(xiàn)高性能配置管理器,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起了解一下
    2023-04-04
  • C++中二叉堆排序詳解

    C++中二叉堆排序詳解

    這篇文章主要介紹了C++中二叉堆排序詳解,主要介紹了二叉堆排序(遞歸和非遞歸實現(xiàn)上沉、下沉算法),需要的朋友可以參考下
    2023-01-01
  • 解析C++編程中virtual聲明的虛函數(shù)以及單個繼承

    解析C++編程中virtual聲明的虛函數(shù)以及單個繼承

    這篇文章主要介紹了C++編程中virtual聲明的虛函數(shù)以及單個繼承,剖析虛函數(shù)和單個基類所能夠繼承的成員,要的朋友可以參考下
    2016-01-01
  • C語言中壓縮字符串的簡單算法小結(jié)

    C語言中壓縮字符串的簡單算法小結(jié)

    這篇文章主要介紹了C語言中可用于實現(xiàn)字符串壓縮的簡單算法小結(jié),列舉了包括哈夫曼算法等三個核心的程序?qū)崿F(xiàn)算法,需要的朋友可以參考下
    2016-03-03
  • C++?二進(jìn)制文件讀寫方式及示例詳解

    C++?二進(jìn)制文件讀寫方式及示例詳解

    這篇文章主要為大家介紹了C++?二進(jìn)制文件讀寫實現(xiàn)方式及示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-04-04
  • 基于C語言實現(xiàn)見縫插針游戲的示例代碼

    基于C語言實現(xiàn)見縫插針游戲的示例代碼

    見縫插針游戲就是使用鼠標(biāo)左鍵點擊發(fā)射針,當(dāng)兩個針的夾角小于一定限制時,游戲結(jié)束。本文將用C語言實現(xiàn)這一有趣游戲,感興趣的可以了解一下
    2022-11-11
  • Cocos2d-x UI開發(fā)之文本類使用實例

    Cocos2d-x UI開發(fā)之文本類使用實例

    這篇文章主要介紹了Cocos2d-x學(xué)習(xí)筆記之文本類,文本類是UI開發(fā)中經(jīng)常使用的,本文用詳細(xì)的代碼注釋講解了文本類的使用,需要的朋友可以參考下
    2014-09-09
  • 使用C語言實現(xiàn)三子棋游戲

    使用C語言實現(xiàn)三子棋游戲

    這篇文章主要為大家詳細(xì)介紹了使用C語言實現(xiàn)三子棋游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-07-07
  • 用c語言實現(xiàn)《狼人殺》游戲發(fā)牌系統(tǒng)

    用c語言實現(xiàn)《狼人殺》游戲發(fā)牌系統(tǒng)

    大家好,本篇文章主要講的是用c語言實現(xiàn)《狼人殺》游戲發(fā)牌系統(tǒng),感興趣的同學(xué)趕快來看一看吧,對你有幫助的話記得收藏一下
    2022-01-01
  • C語言實現(xiàn)3個數(shù)從小到大排序/輸出的方法示例

    C語言實現(xiàn)3個數(shù)從小到大排序/輸出的方法示例

    這篇文章主要給大家介紹了關(guān)于如何利用C語言實現(xiàn)3個數(shù)從小到大排序/輸出的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用C語言具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-05-05

最新評論

台南县| 合肥市| 周宁县| 噶尔县| 嘉峪关市| 明溪县| 瓦房店市| 滨海县| 河源市| 双桥区| 荥经县| 郁南县| 沾益县| 绵竹市| 大竹县| 宁远县| 宜兴市| 南康市| 安泽县| 吉木乃县| 朝阳区| 谢通门县| 灵武市| 新乡县| 延寿县| 武功县| 霍山县| 隆林| 贵南县| 平舆县| 尤溪县| 营山县| 东台市| 定安县| 晋州市| 云浮市| 塘沽区| 鲁山县| 弥渡县| 安溪县| 田阳县|