国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

函數(shù)棧幀的創(chuàng)建與銷毀

這篇具有很好參考價值的文章主要介紹了函數(shù)棧幀的創(chuàng)建與銷毀。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

函數(shù)棧幀的創(chuàng)建與銷毀,魔王的修煉之路——C語言,c語言,c++,算法

  • 魔王的介紹:??????一名雙非本科大一小白。
  • 魔王的目標:??努力趕上周圍卷王的腳步。
  • 魔王的主頁:??????大魔王.??????
    函數(shù)棧幀的創(chuàng)建與銷毀,魔王的修煉之路——C語言,c語言,c++,算法
    ?????大魔王與你分享:莫泊桑說過,生活可能不像你想象的那么好,但是也不會像你想象的那么糟。人的脆弱和堅強都超乎了自己的想象。有時候可能脆弱的一句話就淚流滿面,有時候你發(fā)現(xiàn)自己咬著牙已經(jīng)走過了很長的路。

一、前言

我們在編譯代碼時會有很多不清楚的地方,例如我們創(chuàng)建變量時我們只知道會開辟空間,卻不知道要在哪開辟,怎么開辟,在我們調用函數(shù)時,我們也知道要在棧區(qū)開辟空間,但是依然不知道怎么開辟,參數(shù)如何拷貝,為什么值傳遞不會改變原數(shù)值。本篇博客帶你理解棧區(qū)(局部變量和函數(shù)調用開辟空間的地方)是怎樣工作的。

二、問題舉例

  • 局部變量是怎么創(chuàng)建的?
  • 為什么局部變量的值是隨機值?
  • 函數(shù)時怎么傳參的?傳參的順序是怎樣的?
  • 形參和實參是什么關系?
  • 函數(shù)調用時怎么做的?
  • 函數(shù)調用時結束后怎樣返回的?
  • 通過下面的講解你將全部明白這些問題

三、介紹

  • 首先說明一些比較陌生的東西,以便后續(xù)的理解。

1.寄存器

  1. 寄存器:中央處理器內的組成部分。寄存器是有限存貯量的高速存貯部件,它們可以來暫存指令、數(shù)據(jù)和地址。寄存器是獨立于內存的,不會因為棧區(qū)函數(shù)空間的銷毀而銷毀。
  2. 寄存器舉例:
    eax、ebx、ecx、edx、ebp、esp等
    其中三個寄存器比較重要:
    1.eax:接收函數(shù)返回值,使得函數(shù)的返回值不會因為棧區(qū)的銷毀而消失。
    2.ebp:棧底寄存器(高地址),和esp共同維護棧區(qū)新開辟的空間。
    3.esp:棧頂寄存器(低地址),和ebp共同維護棧區(qū)新開辟的空間。

2.匯編指令

push:壓棧,放入棧頂一個元素(寄存器的內容,并不是寄存器)。
pop:出棧,把棧頂數(shù)據(jù)彈出,并把彈出的元素賦值到寄存器中。
move:給一個寄存器賦值。
sub:減法指令。
add:加法指令。
lea:即load effective address,加載有效地址。
call:調用函數(shù),并且把該函數(shù)之后的地址進行壓棧(目的是為了在函數(shù)銷毀后可以回到函數(shù)之后的下一步)。
dword:即double word,可以理解為兩倍的字的大小,我們知道一個漢字兩個字節(jié),那么兩倍的就是四個字節(jié)。
rep stors:重復拷貝寄存器中的數(shù)據(jù)。
注意:esp永遠指向棧頂,每次壓棧后esp就會自動減去4個字節(jié)(因為棧區(qū)的使用是高地址向低地址使用),每次出棧后esp就會加上4個字節(jié)。

四、講解

  • 以此代碼為標準進行詳細說明:
#include <stdio.h>
int Add(int x, int y)
{
	int z = 0;
	z = x + y;
	return z;
}
int main()
{
	int a = 10;
	int b = 20;
	int c = 0;
	c = Add(a, b);
	printf("%d\n", c);
	return 0;
}

1.main函數(shù)并不是最終函數(shù)

我們一直認為main函數(shù)結束,程序就會結束,main函數(shù)是程序的最后一個函數(shù),你是否想過這樣一個問題:為什么main函數(shù)會有返回值呢?那自然是因為main函數(shù)并不是最終函數(shù),main函數(shù)也是被其他函數(shù)所調用的。我們轉到調用堆棧就會觀察到,如圖:

函數(shù)棧幀的創(chuàng)建與銷毀,魔王的修煉之路——C語言,c語言,c++,算法

  • 那么到底是什么函數(shù)調用的main函數(shù)呢?
    函數(shù)棧幀的創(chuàng)建與銷毀,魔王的修煉之路——C語言,c語言,c++,算法

是__tmainCRTStartup函數(shù)調用的main函數(shù)。__tmainCRTStartup函數(shù)又是被mainCRTStartup函數(shù)調用的。

  • 也就是main函數(shù)后其實還有兩個函數(shù),如圖:函數(shù)棧幀的創(chuàng)建與銷毀,魔王的修煉之路——C語言,c語言,c++,算法

所畫的圖只表示調用順序和棧幀使用順序(先使用高地址在使用低地址)。

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

函數(shù)棧幀怎樣創(chuàng)建,我們可以通過反匯編觀察得到。要進入反匯編,首先要進入調試,然后按照圖片操作即可進入,如圖:

函數(shù)棧幀的創(chuàng)建與銷毀,魔王的修煉之路——C語言,c語言,c++,算法

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

函數(shù)棧幀創(chuàng)建的邏輯基本一樣,所以詳細說一個怎么創(chuàng)建,其他就基本也是這樣,這里以主函數(shù)舉例。通過圖一點點進行分析,如圖:函數(shù)棧幀的創(chuàng)建與銷毀,魔王的修煉之路——C語言,c語言,c++,算法

所畫的15個指令是在Add函數(shù)之前的匯編指令,前10個指令是創(chuàng)建主函數(shù)的棧幀空間并賦值為CCCCCCCC,這就是當我們不給一個變量賦值時,會打印出燙燙燙燙的原因。第11、12這兩個指令是新增的,在VS2013上并沒有,所以無視就行。那么從第13個指令開始,就該使用所開辟好的空間了。詳細如下:

  1. 用ebp的值進行壓棧。然后esp-4(沒個元素都是4個字節(jié),棧區(qū)的使用是從高地址向低地址使用的)。
  2. 把esp的值賦給ebp。
  3. 讓esp減去0E4h這個十六進制數(shù)字。(目的是給main函數(shù)開辟空間,esp是維護棧頂?shù)模砸宔sp移動到新開辟的棧頂位置)
  4. 用ebx的值進行壓棧。
  5. 用esi的值進行壓棧。
  6. 用edi的值進行壓棧。
  7. load effective address,加載有效地址。放入edi中。
  8. 把9賦值到ecx中。
  9. 把CCCCCCCC賦值到eax中。
  10. 重復拷貝:從edi(加載的那個有效地址)開始,拷貝ecx次(9),每次拷貝eax(CCCCCCCC),每次拷貝的大小為dword(4字節(jié))。每拷貝一次,edi(存放有效地址的這個寄存器都加4),ecx(存放拷貝次數(shù)的寄存器都減1),直到ecx減到0,停止拷貝,執(zhí)行下一個匯編指令。
    前十個是為main函數(shù)開辟空間并賦值為CCCCCCCC的匯編碼。接下來才開始讓我們寫的程序分配空間。
  11. 在ebp-8位置處賦值0Ah(也就是10).
  12. 在ebp-14h(ebp-20)位置處賦值14h(也就是20)
  13. 在ebp-20h(ebp-32)位置處賦值0
  • 如圖:
    函數(shù)棧幀的創(chuàng)建與銷毀,魔王的修煉之路——C語言,c語言,c++,算法

第一個圖其實__tmainCRTStartup函數(shù)是被mainCRTStartup函數(shù)調用的,不過這里就不畫了,我們主要是理解main函數(shù)及main函數(shù)內的函數(shù)調用如何在棧區(qū)開辟空間就好了,main函數(shù)之前的那兩個函數(shù)知道有就行了。

這個圖如果在VS2013是正確的,開辟的空間全部先初始化,但是在VS2022中,其實開辟的主函數(shù)的空間并沒有全部賦值,如圖:

函數(shù)棧幀的創(chuàng)建與銷毀,魔王的修煉之路——C語言,c語言,c++,算法

  • 最后一次拷貝后的內存展示:函數(shù)棧幀的創(chuàng)建與銷毀,魔王的修煉之路——C語言,c語言,c++,算法

3.函數(shù)調用

開辟空間前執(zhí)行的操作:

  • 函數(shù)調用的時候,我們都知道會開辟空間,但是他是怎么開辟的呢?
  • 我們知道形參是實參的臨時拷貝,那么它是怎樣拷貝的呢?
  • 我們知道函數(shù)結束后該函數(shù)所處的棧幀空間就要被銷毀回收,那么如果該函數(shù)有返回值,明明已經(jīng)被銷毀了,它是怎樣再返回去的呢?
    接著往下看,你就會全部知道。
  • 在調用函數(shù)這個操作中,剛開始進行的是讓實參(實參地址中的內容那就是實參的數(shù)值)賦給eax,ecx,從右向左壓棧,也就是先壓棧b的值,再壓棧a的值,這就是反匯編的前四行。其實這四行目的就是拷貝實參。第五行call指令是調用Add這個函數(shù)并且把調用Add函數(shù)后的下一個操作指令進行壓棧,目的是為了在調用函數(shù)結束后,可以回到Add函數(shù)之后的下一步指令。
    函數(shù)棧幀的創(chuàng)建與銷毀,魔王的修煉之路——C語言,c語言,c++,算法

開辟空間及銷毀前的操作:

  • 匯編指令如圖:函數(shù)棧幀的創(chuàng)建與銷毀,魔王的修煉之路——C語言,c語言,c++,算法
    函數(shù)棧幀的創(chuàng)建與銷毀,魔王的修煉之路——C語言,c語言,c++,算法

紅色框不含黃色部分:
還是和之前main函數(shù)開辟一樣,先是壓棧ebp,然后讓ebp移動到esp位置,然后esp減去一個數(shù)值(即開辟的空間大?。?,然后進行(部分)(不同編譯器可能不一樣,有可能使部分賦值,有可能是整個空間賦值)賦值,賦值為CCCCCCCC,然后就是為Add函數(shù)中的變量分配空間(如下圖)。
紅色框中的黃色部分:
這個部分是關于函數(shù)返回值的匯編指令,兩個圖結合看,ebp+8的值賦給eax(是寄存器,獨立于內存,不會因為棧幀空間銷毀而銷毀),然后讓eax的值加上ebp+0Ch這個地址的值,這個地址轉換為十進制也就是ebp+12,再讓eax的值賦給該函數(shù)中的變量z,所以函數(shù)的返回值也就暫時儲存在了寄存器eax中(因此當z被銷毀后,eax里還存著函數(shù)的返回值,等待之后的指令),那么你是否發(fā)現(xiàn)了,ebp+8其實就是在開辟函數(shù)空間前拷貝的10,ebp+12就是開辟空間前拷貝的20,所以eax就變成了30,也就是說函數(shù)使用的實參其實在自己內部空間根本就沒有,他們只是通過地址訪問了在開辟函數(shù)空間前壓棧的那些形參,僅僅是使用而已,因此值傳遞不改變原數(shù)值。

銷毀操作:

函數(shù)棧幀的創(chuàng)建與銷毀,魔王的修煉之路——C語言,c語言,c++,算法

  • 按照老編譯器(老編譯器中沒有劃掉的那三行)來說:
  • 第1步:把z的值賦給eax,因為z要銷毀了,但是返回值要被保留,所以要借助寄存器保留下來。
  • 2~4步:pop指令,也就是出棧,最上面的三個元素,并把元素的值分別賦給edi、esi、ebx,其實這三個pop指令中的賦值操作沒用,因為彈出的是edi,edi里邊本來存的就是edi的值。其他兩個也是這樣。但是對于倒數(shù)第二行的pop指令中的賦值操作就用處很大了,接著看,等會會說到(第6步)。
  • 第5步:把ebp的值賦給esp,那就是說esp離開了正在維護的函數(shù)的棧幀空間,那么這一部分就讓函數(shù)棧幀空間被銷毀了。
  • 第6步:出棧,并且把出棧的值(是ebp指向main函數(shù)底部時壓棧上去的那個地址,也就是說出棧的這個元素其實存放的是main函數(shù)的棧底指針)賦給寄存器ebp。那么ebp就回到原來的位置了。(main函數(shù)的棧底指針處)
  • 第七步:ret,即返回,這一步也很重要,它的意義是彈出并回到彈出的這個地址所指向的指令,因為第六步我們只是讓ebp回到了main的棧底位置,此時esp和ebp位置都就緒了,但是指令卻還沒有返回,而這一步其實就是彈出了調用函數(shù)之后的那個指令的地址(之前壓棧上去的那個),并且回到彈出這個指令的位置,也就是調用函數(shù)的下一個指令的位置,那么一切便結束了,后面就是調用函數(shù)之后的操作了。

4.調用函數(shù)后的匯編指令:

  • 最后兩行指令:
    函數(shù)棧幀的創(chuàng)建與銷毀,魔王的修煉之路——C語言,c語言,c++,算法
  • 目前的棧幀圖:
    函數(shù)棧幀的創(chuàng)建與銷毀,魔王的修煉之路——C語言,c語言,c++,算法

第一個指令esp加8,那么就是說esp跳過了臨時拷貝的變量,也就是銷毀了臨時拷貝形參的棧幀空間。
第二個指令就是把eax寄存器中存的函數(shù)的返回值賦到main函數(shù)中接收Add函數(shù)返回值的地址中,也就是變量c的位置,往上翻看看前面你就會發(fā)現(xiàn)變量c的地址就是eax要賦的地址處。

  • 那么相信你看完函數(shù)棧幀的創(chuàng)建于銷毀后對棧幀空間的運行原理有了更深層次的理解。

五、總結

函數(shù)棧幀的創(chuàng)建與銷毀,魔王的修煉之路——C語言,c語言,c++,算法

?請點擊下面進入主頁關注大魔王
如果感覺對你有用的話,就點我進入主頁關注我吧!文章來源地址http://www.zghlxwxcb.cn/news/detail-618163.html

到了這里,關于函數(shù)棧幀的創(chuàng)建與銷毀的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。如若轉載,請注明出處: 如若內容造成侵權/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領支付寶紅包贊助服務器費用

相關文章

  • C語言之反匯編查看函數(shù)棧幀的創(chuàng)建與銷毀

    C語言之反匯編查看函數(shù)棧幀的創(chuàng)建與銷毀

    函數(shù)棧幀是用于在計算機程序中實現(xiàn)函數(shù)調用的一種數(shù)據(jù)結構。在函數(shù)調用過程中,每個函數(shù)都需要在內存中創(chuàng)建一個棧幀,用于存儲局部變量、返回地址和參數(shù)等。 具體來說,函數(shù)棧幀通常包含以下部分: 局部變量表:存儲函數(shù)的局部變量,包括基本數(shù)據(jù)類型(如整數(shù)、

    2024年01月23日
    瀏覽(16)
  • 【C語言__函數(shù)棧幀的創(chuàng)建和銷毀__復習篇9】

    【C語言__函數(shù)棧幀的創(chuàng)建和銷毀__復習篇9】

    目錄 前言 一、知識補充 二、分析創(chuàng)建和銷毀的過程 三、前言問題回答 本篇主要討論以下問題: 1. 編譯器什么時候為局部變量分配的空間 2. 為什么局部變量的值是隨機的 3. 函數(shù)是怎么傳參的,傳參的順序是怎樣的 4. 形參和實參是什么關系 5. 函數(shù)調用是怎么做的 6. 函數(shù)調

    2024年04月25日
    瀏覽(20)
  • 打通你學習C語言的任督二脈-函數(shù)棧幀的創(chuàng)建和銷毀(上)

    打通你學習C語言的任督二脈-函數(shù)棧幀的創(chuàng)建和銷毀(上)

    ? ??個人主頁:? Aileen_0v0 ??系列專欄: C語言學習 ??個人格言: \\\"沒有羅馬,那就自己創(chuàng)造羅馬~\\\" 待解決疑惑: 局部變量是怎么創(chuàng)建的? 為什么局部變量的值是隨機值? 函數(shù)是怎么傳參的?傳參的順序是怎樣的? 形參和實參是什么關系? 函數(shù)調用是怎么做的? 函數(shù)調用是結束后怎么返

    2024年02月05日
    瀏覽(22)
  • 函數(shù)棧幀的創(chuàng)建與銷毀

    函數(shù)棧幀的創(chuàng)建與銷毀

    魔王的介紹:??????一名雙非本科大一小白。 魔王的目標:??努力趕上周圍卷王的腳步。 魔王的主頁:??????大魔王.?????? ?????大魔王與你分享:莫泊桑說過,生活可能不像你想象的那么好,但是也不會像你想象的那么糟。人的脆弱和堅強都超乎了自己的想

    2024年02月15日
    瀏覽(18)
  • 函數(shù)棧幀的創(chuàng)建和銷毀

    函數(shù)棧幀的創(chuàng)建和銷毀

    前言 觀察函數(shù)棧幀的創(chuàng)建和銷毀,不要使用太高級別的的編譯器,越高級的編譯器越不容易學習和觀察。同時在不同編譯器下,函數(shù)調用的過程中棧幀的創(chuàng)建是略有差異的,具體細節(jié)取決于編譯器的實現(xiàn) 我們在寫C語言代碼的時候,經(jīng)常會把一個獨立的功能抽象為函數(shù),所以

    2023年04月17日
    瀏覽(21)
  • 從匯編代碼探究函數(shù)棧幀的創(chuàng)建和銷毀的底層原理

    從匯編代碼探究函數(shù)棧幀的創(chuàng)建和銷毀的底層原理

    人,只有在放棄戰(zhàn)斗的時候才算輸,只要堅持戰(zhàn)斗,就還沒輸? 本文收錄于青花霧氣-計算機基礎 往期回顧 從0到1搞定在線OJ 數(shù)據(jù)在內存中的存儲 計算機存儲的大小端模式 目錄 一、先導知識 二、函數(shù)調用堆棧 三、函數(shù)棧幀的創(chuàng)建 1.創(chuàng)建函數(shù)棧幀 2.創(chuàng)建變量 3.函數(shù)傳參 4.函數(shù)

    2024年02月08日
    瀏覽(13)
  • 【C語言】函數(shù)棧幀的創(chuàng)建和毀銷

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

    大家好,我是深魚~ 目錄 一、寄存器 二、棧區(qū) ?三、函數(shù)棧幀的創(chuàng)建 1.為main函數(shù)開辟棧幀? 2.在main函數(shù)中創(chuàng)建變量 3.調用Add函數(shù)前的準備 ?4.為Add函數(shù)開辟棧幀 ?5.在Add函數(shù)中創(chuàng)建變量并運算 四、函數(shù)棧幀的銷毀 6.Add函數(shù)棧幀的銷毀 7.返回main函數(shù)棧幀 【前言】 前期學習的時

    2024年02月14日
    瀏覽(15)
  • 函數(shù)棧幀的創(chuàng)建和毀銷【C語言版】

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

    大家好,我是深魚~ 目錄 一、寄存器 二、棧區(qū) ?三、函數(shù)棧幀的創(chuàng)建 1.為main函數(shù)開辟棧幀? 2.在main函數(shù)中創(chuàng)建變量 3.調用Add函數(shù)前的準備 ?4.為Add函數(shù)開辟棧幀 ?5.在Add函數(shù)中創(chuàng)建變量并運算 四、函數(shù)棧幀的銷毀 6.Add函數(shù)棧幀的銷毀 7.返回main函數(shù)棧幀 【前言】 前期學習的時

    2024年02月15日
    瀏覽(21)
  • 探秘函數(shù)棧幀:『 揭開函數(shù)棧幀創(chuàng)建與銷毀的神秘面紗 』

    探秘函數(shù)棧幀:『 揭開函數(shù)棧幀創(chuàng)建與銷毀的神秘面紗 』

    .. 目錄 知識點回顧 一、什么是棧幀(堆棧幀)? 1.內存布局 2.常用寄存器 3.匯編指令 ????對于棧的詳細介紹 : ????函數(shù)棧幀的介紹: 二、函數(shù)調用中的棧幀 1.探究main函數(shù)棧幀的創(chuàng)建 2.對main函數(shù)中的代碼進行分析 3.探究Add函數(shù)棧幀的創(chuàng)建? 三、函數(shù)棧幀的銷毀過程 博客引

    2024年02月06日
    瀏覽(29)
  • 學C的第十一天【查看匯編代碼一步步了解 函數(shù)棧幀(棧區(qū)局部變量)的創(chuàng)建和銷毀】

    學C的第十一天【查看匯編代碼一步步了解 函數(shù)棧幀(棧區(qū)局部變量)的創(chuàng)建和銷毀】

    ========================================================================= 相關代碼gitee自?。?C語言學習日記: 加油努力 (gitee.com) ========================================================================= 接上期: 學C的第十天(繼續(xù)深入學習函數(shù)、函數(shù)遞歸、練習)-CSDN博客 ============================================

    2024年02月04日
    瀏覽(49)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領取紅包,優(yōu)惠每天領

二維碼1

領取紅包

二維碼2

領紅包