函式呼叫時發生了什麼

2021-06-05 17:34:26 字數 1524 閱讀 6575

我們下面就來**一下高階語言中函式的呼叫和遞迴等性質是怎樣通過系統棧巧妙實現的。請看如下**:

int func_b(int arg_b1, int arg_b2)

int func_a(int arg_a1, int arg_a2)

int main(int argc, char **argv, char **envp)

這段**經過編譯器編譯後,各個函式對應的機器指令在**區中可能是這樣分布的,如圖4.1.2所示。

根據作業系統的不同、編譯器和編譯選項的不同,同一檔案不同函式的**在記憶體**區中的分布可能相鄰,也可能相離甚遠;可能先後有序,也可能無序;但它們都在同乙個pe檔案的**所對映的乙個「節」裡。我們可以簡單地把它們在記憶體**區中的分布位置理解成是散亂無關的。

當cpu在執行呼叫func_a函式的時候,會從**區中main函式對應的機器指令的區域跳轉到func_a函式對應的機器指令區域,在那裡取指並執行;當func_a函式執行完閉,需要返回的時候,又會跳回到main函式對應的指令區域,緊接著呼叫func_a後面的指令繼續執行main函式的**。在這個過程中,cpu的取指軌跡如圖4.1.3所示。

圖4.1.2 函式**在**區              圖4.1.3 cpu在**區中的取指軌跡示意圖  

中的分布示意圖

那麼cpu是怎麼知道要去func_a的**區取指,在執行完func_a後又是怎麼知道跳回到main函式(而不是func_b的**區)的呢?這些跳轉位址我們在c語言中並沒有直接說明,cpu是從**獲得這些函式的呼叫及返回的資訊的呢?

原來,這些**區中精確的跳轉都是在與系統棧巧妙地配合過程中完成的。當函式被呼叫時,系統棧會為這個函式開闢乙個新的棧幀,並把它壓入棧中。這個棧幀中的記憶體空間被它所屬的函式獨佔,正常情況下是不會和別的函式共享的。當函式返回時,系統棧會彈出該函式所對應的棧幀。

圖4.1.4 系統棧在函式呼叫時的變化

如圖4.1.4所示,在函式呼叫的過程中,伴隨的系統棧中的操作如下。

在main函式呼叫func_a的時候,首先在自己的棧幀中壓入函式返回位址,然後為func_a建立新棧幀並壓入系統棧。

在func_a呼叫func_b的時候,同樣先在自己的棧幀中壓入函式返回位址,然後為func_b建立新棧幀並壓入系統棧。

在func_b返回時,func_b的棧幀被彈出系統棧,func_a棧幀中的返回位址被「露」在棧頂,此時處理器按照這個返回位址重新跳到func_a**區中執行。

在func_a返回時,func_a的棧幀被彈出系統棧,main函式棧幀中的返回位址被「露」在棧頂,此時處理器按照這個返回位址跳到main函式**區中執行。

題外話:在實際執行中,main函式並不是第乙個被呼叫的函式,程式被裝入記憶體前還有一些其他操作,圖4.1.4只是棧在函式呼叫過程中所起作用的示意圖。

函式呼叫時發生了什麼

第一步 函式呼叫 1 對實參表從右向左,一次計算出實參的值,並且將值壓棧。2 將函式呼叫語句 儲存到在棧中,以便函式呼叫完成後返回。壓棧 3 跳轉到函式體處。第二步 函式體執行 4 如果函式體中定義了變數,將變數壓棧 5 將每乙個形參以棧中對應的 實參值取代,執行函式體的功能體。6 將函式體中的變數...

函式呼叫時發生了什麼?

我們以如下 示例,描述函式呼叫過程中,棧的操作過程 voidf intg int x 每次函式呼叫,作業系統都會在棧中建立乙個棧幀 stack frame 正在執行的函式引數 區域性變數 申請的記憶體位址等都在當前棧幀中,也就是堆疊的頂部棧幀中。如下圖所示 當 f 函式執行的時候,f 函式就在棧頂,...

函式呼叫的時候棧發生了什麼?

問題分析 本文分析的問題是函式的棧呼叫機理。先說結論 所謂的暫存器入棧 實際上是指的一組暫存器入棧。因為在新呼叫的函式中,這些暫存器仍然會被用到,為了退出呼叫函式後能恢復狀態,凡是有可能被修改的暫存器都要入棧。出棧順序和入棧順序相反。這個過程由編譯器維護。在現在普遍應用的單指令流,單資料流計算機上,...