欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C語言函數(shù)棧幀詳解

 更新時間:2021年10月18日 11:08:42   作者:Zero0Tw0  
下面小編就為大家?guī)硪黄獪\談C語言函數(shù)調用參數(shù)壓棧的相關問題。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

前言

在c語言中我們會將一些功能單獨寫成一個函數(shù),以供主函數(shù)調用,在表面來看調用的過程就是寫出一個函數(shù)后,只需要在調用時中通過函數(shù)名將實參傳給形參就實現(xiàn)了整個過程,但實際上調用的過程遠比你想的復雜,這其中函數(shù)棧幀起著關鍵作用。通過本篇文章,我將告訴你函數(shù)在調用時計算機內究竟發(fā)生了什么?

一.函數(shù)棧幀是什么?

C語言中,每個棧幀對應著一個未運行完的函數(shù)。棧幀中保存了該函數(shù)的返回地址和局部變量。(來自百度百科)。

通過這句話我們可以提煉出兩個關鍵信息:

1.每個未運行完的函數(shù)都有一個對應的棧幀

2.棧幀保存了函數(shù)的返回地址和局部變量

先對棧幀有一個簡單的概念,知道其主要作用是什么就行。

二、棧幀準備知識

由于函數(shù)棧幀不光涉及c語言代碼知識,如果是小白一定要認真看本節(jié),這對幫助你理解棧幀非常重要,也不要因為發(fā)現(xiàn)這些知識你之前完全沒聽說過就產(chǎn)生畏難心理,事實上,我們只需要掌握期其中一些非常關鍵的地方就足夠了。

1.內存分區(qū)

內存中主要分為棧區(qū),堆區(qū),靜態(tài)區(qū),以及其他部分。

棧區(qū):由高地址往低地址增長,主要用來存放局部變量,函數(shù)調用開辟的空間,與堆共享一段空間。(本篇重點)

堆區(qū):由地地址向高地址增長,動態(tài)開辟的空間就在這里(malloc,realloc,calloc,free),與棧共享一段空間。

靜態(tài)區(qū):主要存放全局變量和靜態(tài)變量。

2.什么是棧?

前面已經(jīng)知道棧中存放了函數(shù)調用開辟的空間即棧幀,因此我們要明白什么是棧幀,必須先知道什么是棧。

棧是一種數(shù)據(jù)結構,是一種只能在一端進行插入和刪除操作的特殊線性表。它按照先進后出的原則存儲數(shù)據(jù),先進入的數(shù)據(jù)被壓入棧底,最后的數(shù)據(jù)在棧頂,需要讀數(shù)據(jù)的時候從棧頂開始彈出數(shù)據(jù)(最后放入的數(shù)據(jù)被最先讀出來)。

簡單來講你可以把棧理解為一個彈夾,而我們放的數(shù)據(jù)就像子彈,當我們射子彈時,總是會把后壓入的彈先射出去,因為后壓入的彈一定是放在最上面的,而先壓入的彈后射出去,因為先壓入的彈在最下面。這就是棧最大的特點"先入后出,后入先出",而往棧中放數(shù)據(jù)我們稱作壓棧(push),拿出棧中的數(shù)據(jù)我們叫出棧(pop)。

壓棧(push):

出棧(pop):

3.esp,ebp,eax寄存器

ebp ebp是基址指針,保存調用者函數(shù)的地址,總是指向當前棧幀棧底
esp esp是被調函數(shù)指針,總指向函數(shù)棧棧頂
eax 累加器,用來乘除法,與函數(shù)返回值(本篇主要關注第二個功能)

簡單來講就是esp和ebp是兩個指針,ebp指向當前棧幀棧底,esp指向函數(shù)棧棧頂。

能看到,ebp并不是指向整個函數(shù)棧的棧底,而是指向當前棧幀的棧底,而由于esp總是指向棧頂,且棧只允許一個方向的操作,因此esp指向其實也是當前棧幀的棧頂,不過當前棧幀的棧頂始終與棧頂相同,因此說esp指向的是棧頂。

三、詳解棧幀創(chuàng)建與銷毀全過程

有了以上知識就能夠初步理解棧幀從創(chuàng)建到銷毀的全過程了,接下來我會一步一步講解

假設我們有當前代碼:

#include<stdio.h>
int add(int a, int b)
{
	int c = 0;
	c = a + b;
	return c;
}
int main()
{
	int a = 1;
	int b = 1;
	int sum;
	sum = add(a, b);
	return 0;
}

調用函數(shù)之前:

此時我們準備執(zhí)行函數(shù)調用"sum = add(a,b);"此時棧中如下:

將傳入函數(shù)的值放入棧中

由于函數(shù)調用涉及到傳參,因此我們在調用函數(shù)之前,需要先將傳入的參數(shù)保存,以方便函數(shù)的調用,因此需要將add函數(shù)的a=1,b=2,push入棧保存

函數(shù)執(zhí)行:

1.保護當前ebp

由于我們馬上要創(chuàng)建新的棧幀空間,因此ebp和esp都得將變動,為了能夠讓我們調用完add函數(shù)后還能讓ebp回到當前位置我們需要對ebp的值進行保護,即將此時ebp的值壓入棧(至于為什么不需要保護esp,看到后面你就能明白)

2.創(chuàng)建所需調用函數(shù)的棧幀空間

令ebp指向當前esp的位置并根據(jù)add函數(shù)的參數(shù)個數(shù),創(chuàng)建一個大小合適的空間。

① ebp指向當前esp的位置

②創(chuàng)建空間

3.保存局部變量

將add函數(shù)中創(chuàng)建的變量"int c = 0"放入剛剛開辟的棧幀空間中

4.參數(shù)運算

根據(jù)形參與局部變量,進行對應的運算,這里執(zhí)行"c = a +b", 得到 c = 2,放入剛才c對應的位置。

到次函數(shù)執(zhí)行就完成了,接下來就要開始實現(xiàn)函數(shù)返回

函數(shù)返回:

1.存儲返回值

現(xiàn)在我們已經(jīng)達成了目的"add(a,b)",要將之前創(chuàng)建的add的函數(shù)棧銷毀,以使得我們能夠回到main函數(shù)中正常執(zhí)行,而在銷毀add的函數(shù)棧幀前我們的main函數(shù)可還沒有拿到運算結果,因此我們需要先將需要返回的值存儲起來,存儲的位置就是前面提到的eax寄存器,這里"return c",我們將c的值放到eax寄存器中。

2.銷毀空間

拿到了運算結果后,我們就沒有任何任何顧慮了,可以直接銷毀函數(shù)的棧楨空間了。

3.ebp回上一棧幀棧底

此時ebp拿到之間存儲的上一棧幀棧底的值,回到相應的位置,于此同時,存儲的ebp沒有用了,也將被銷毀。

4.銷毀形參

形參也不再有用,因此也隨即銷毀。(這里也讓我們明白:由于形參在調用完函數(shù)后就會銷毀,且與實參根本不是同一地址,因此形參的改變無法影響實參。)

5.main函數(shù)拿到返回值

在講解main函數(shù)怎么拿到返回值前,我想先問一個問題:

上圖中所謂的前一棧幀指的是什么?

大家都知道,我們編寫的c程序都是從一個main函數(shù)開始的,實際上,代碼并不是直接從main函數(shù)開始運行的,main函數(shù)的本質也是一個被其他代碼調用的函數(shù),至于被誰調用,這里就不展開講解了,這里提出這個問題是想要大家知道:

main函數(shù)是一個函數(shù),它有自己的棧幀。

因此所謂的前一棧幀實際上就是調用add函數(shù)的main函數(shù)的棧幀。

因此我們要讓main函數(shù)拿到返回值,只需要把eax寄存器中的值放入main棧幀中sum對應的位置就行。(這里也能讓我們明白:由于我們只有一個eax寄存器,因此c語言的函數(shù)只能有一個返回值。)

至此棧幀的創(chuàng)建與銷毀結束,函數(shù)調用完成。

總結

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

相關文章

  • C++實現(xiàn)編碼轉換的示例代碼

    C++實現(xiàn)編碼轉換的示例代碼

    這篇文章主要介紹了C++實現(xiàn)編碼轉換的示例代碼,幫助大家快捷的實現(xiàn)編碼轉換,感興趣的朋友可以了解下
    2020-08-08
  • C語言的數(shù)字游戲算法效率問題探討實例

    C語言的數(shù)字游戲算法效率問題探討實例

    這篇文章主要介紹了C語言的數(shù)字游戲算法效率問題探討實例,需要的朋友可以參考下
    2014-04-04
  • C語言實現(xiàn)貪吃蛇游戲

    C語言實現(xiàn)貪吃蛇游戲

    這篇文章主要為大家詳細介紹了C語言實現(xiàn)貪吃蛇游戲,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-03-03
  • 詳解state狀態(tài)模式及在C++設計模式編程中的使用實例

    詳解state狀態(tài)模式及在C++設計模式編程中的使用實例

    這篇文章主要介紹了state狀態(tài)模式及在C++設計模式編程中的使用實例,在設計模式中策略用來處理算法變化,而狀態(tài)則是透明地處理狀態(tài)變化,需要的朋友可以參考下
    2016-03-03
  • C++?OpenCV紅綠燈檢測Demo實現(xiàn)詳解

    C++?OpenCV紅綠燈檢測Demo實現(xiàn)詳解

    OpenCV(Open Source Computer Vision Library)是開源的計算機視覺和機器學習庫,提供了C++、 C、 Python、 Java接口,并支持Windows、 Linux、 Android、 Mac OS平臺,下面這篇文章主要給大家介紹了關于C++?OpenCV紅綠燈檢測Demo實現(xiàn)的相關資料,需要的朋友可以參考下
    2022-11-11
  • 簡述C語言中system()函數(shù)與vfork()函數(shù)的使用方法

    簡述C語言中system()函數(shù)與vfork()函數(shù)的使用方法

    這篇文章主要介紹了簡述C語言中system()函數(shù)與vfork()函數(shù)的使用方法,是C語言入門學習中的基礎知識,需要的朋友可以參考下
    2015-08-08
  • 優(yōu)先隊列(priority_queue)的C語言實現(xiàn)代碼

    優(yōu)先隊列(priority_queue)的C語言實現(xiàn)代碼

    本文簡要介紹一種基于數(shù)組二叉堆實現(xiàn)的優(yōu)先隊列,定義的數(shù)據(jù)結構和實現(xiàn)的函數(shù)接口說明如下
    2013-10-10
  • OpenGL畫bezier曲線

    OpenGL畫bezier曲線

    這篇文章主要為大家詳細介紹了OpenGL畫bezier曲線,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-04-04
  • C語言基礎雙指針移除元素解法

    C語言基礎雙指針移除元素解法

    這篇文章介紹了C語言基礎雙指針移除元素的解法,文中通過示例代碼介紹的非常詳細。對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-12-12
  • Qt實現(xiàn)數(shù)據(jù)導出到xls的示例代碼

    Qt實現(xiàn)數(shù)據(jù)導出到xls的示例代碼

    導入導出數(shù)據(jù)到csv由于語法簡單,適用場景有限,于是本文將為大家介紹Qt如何實現(xiàn)導出數(shù)據(jù)到xls,感興趣的小伙伴可以跟隨小編一起試一試
    2022-01-01

最新評論