C語言重中之重,棧幀以及函式的呼叫過程。

2021-08-19 17:44:09 字數 2554 閱讀 3689

首先需要知道cpu所做的事就是不停地讀取程式,分析程式,執行程式。。。還有我們對記憶體的操作都是以位元組為單位。

既然讀取程式是從記憶體上讀取的

那麼也要知道記憶體是怎麼分配的,按照什麼原則分配。這裡先對記憶體做個初步介紹。

用一張**釋:

其中堆疊相對而生,堆區向上增長,棧區向下增長,棧區記憶體用完即銷,堆區需要程式設計師自己申請並自己釋放,若不釋放則會造成記憶體洩漏,或者程式結束時自動釋放(這就是為什麼有時候需要重啟程式或機器的原因)。

【什麼是棧幀結構?】

我的理解中棧幀結構就是在程式執行期間,在記憶體中的棧區開闢和釋放的空間。乙個程式中每個函式在被呼叫之時都會有自己的棧幀結構,當被呼叫完之後就會被釋放,這個棧幀結構由cpu中的ebp(棧底)和esp(棧頂)暫存器來維護。

【cpu中存在一些暫存器】

eap,ebp,ecp,exp這些都是通用暫存器

ebp:棧底暫存器        esp:棧頂暫存器

在呼叫乙個函式的時候用的是組合語言中的call命令,call命令的作用是儲存當前指令的下一條指令的位址,可能有人會問為什麼要儲存?那我想問問你出去玩完回不回家?他又問為什麼儲存的是下一條指令的位址?難道你剛回家就又要出去幹同樣一件事嗎?儲存在**請繼續往下看。

【下面用乙個簡單的程式來完整了解一下程式的呼叫過程】

#includeint add(int x,int y)

int main()

【在以往,我們都錯誤地以為main函式是入口函式】那麼我們呼叫堆疊看看:

由此得出maincrtstartup函式才是入口函式,而main函式只不過是被它呼叫的。

由於main函式實際上是被呼叫的所以它就有自己的棧幀結構。

【進入單步除錯,仔細研究函式的每乙個過程】

注:隨時開啟暫存器和記憶體注意觀察。

檢視程式的反彙編,按f11進入main函式,邊按f11邊觀察暫存器和記憶體的變化,在呼叫函式之前暫停一會,

觀察暫存器和記憶體:

找到指向棧頂和棧底的暫存器,再在記憶體中找到對應區間進行觀察

觀查匯程式設計序

【下面仔細觀察形參例項化環節】

先是形參例項化的過程,仔細觀察

在上面先是將a=10放到了ebp-4的記憶體上,然後給ebp-8這塊記憶體起個名字叫b,並且其內容為10

在這裡卻先是ebp-8,然後才是ebp-4。

原因很簡單,形參例項化的順序是從右往左的。

【call命令】

按一下f11

彙編:暫存器:

再按一下

彙編:暫存器:

再按

【被調函式的棧幀結構形成過程】

參考上文

【關於返回值的問題】

既然被調函式有返回值,但是返回值是區域性變數,隨著函式的呼叫結束棧幀結構不復存在,區域性變數也被銷毀,那麼返回值是怎麼返回到main函式中的?

發現了嗎?返回時是本身銷毀了,返回的是乙份拷貝,在被調函式中計算結果,將結果存入暫存器eax,而return 返回的時候返回的是暫存器中的值,簡而言之,返回值是通過暫存器返回的。

【總結】如圖

C語言函式棧幀解析

目錄 eax,ebx,ecx ebp 存放了指向函式棧幀棧底的位址 esp 存放了指向函式棧幀棧頂的位址 函式被呼叫時,系統會在棧區為該函式開闢一塊棧空間,這個棧空間就是該函式的函式棧幀。以main函式的呼叫為例 棧幀也叫過程活動記錄,是編譯器用來實現函式呼叫過程的一種資料結構。從邏輯上講,棧幀為乙...

C語言 深度理解函式 函式的棧幀

c語言函式是如何呼叫的呢?初學時我想當然地回答 從呼叫部分轉到函式部分逐句執行,就是那麼簡單啊,然而你有沒有想過 函式呼叫前需要做哪些準備工作?函式是如何傳參的?傳參後又是如何使用的?引數使用完後又是如何銷毀的?呼叫的整個過程是怎樣的呢?今天就通過下面這個簡單的 帶大家走進函式的世界,一 竟 inc...

C語言 函式呼叫過程(棧幀)

首先舉個栗子 include int add int x,int y int main 在這個程式裡,函式被呼叫才會發揮函式的功能,而函式的呼叫其實是乙個過程,在這個過程計算機要為函式開闢棧空間,用於本次函式臨時變數的儲存和現場保護,這塊空間稱為函式的棧幀。現場保護的作用是為了在呼叫完另乙個函式,返...