第一步:函式呼叫
1、對實參表從右向左,一次計算出實參的值,並且將值壓棧。
2、將函式呼叫語句
儲存到在棧中,以便函式呼叫完成後返回。(壓棧)
3、跳轉到函式體處。
第二步:函式體執行
4、如果函式體中定義了變數,將變數壓棧
5、將每乙個形參以棧中對應的
實參值取代,執行函式體的功能體。
6、將函式體中的變數、儲存到棧中的實參值,依次從棧中取出,釋放棧空間(出棧)。
第三步:返回
7、返回過程執行的是函式體中的
return
return
語句不帶有表示式時,按照儲存的位址返回,當
return
語句帶有表示式時,將計算出的
return
表示式的值儲存起來,然後再返回。
函式的呼叫方和被呼叫方對於函式如何呼叫需要遵守同樣的約定,函式才能被正確地呼叫,這樣的約定稱為**呼叫慣例**。
* 函式引數的傳遞順序和方式
呼叫慣例要規定引數壓棧的順序:是從左至右,還是從右至左。有些呼叫慣例還允許使用暫存器傳遞引數,以提高效能。
* 棧的維護方式
在被調函式返回時,需要將被壓入棧中的引數全部彈出,以使得棧在函式呼叫前後保持一致。這個彈出的工作可以由函式的呼叫方完成,也也可以由被函式完成。
* 名字修飾規則
為了鏈結的時候對呼叫慣例進行區分,呼叫慣例要對函式本身的名字進行修飾,不同的呼叫慣例有不同的名字修飾策略。
函式返回值傳遞
一般情況下,暫存器eax是傳遞返回值的通道,函式將返回值儲存在eax中,返回後函式的呼叫方再讀取eax。但是eax本身只有4位元組,那麼大於4位元組的返回值是如何傳遞的呢?
對於返回5~8
位元組資料的情況,一般採用eax和edx聯合返回的方式進行的。其中eax儲存返回值的低4位元組,edx儲存返回值的高4位元組。
那麼實際上,編譯器是怎麼設計大尺寸返回值傳遞的呢?
【總結】
函式返回值的傳遞:小於8位元組的返回值,以暫存器為中轉。大於8位元組的,以主調函式中新開闢的同樣大小的中間變數temp為中轉。c
語言對於尺寸太大的返回值型別,會使用乙個臨時的棧上記憶體區域作為中轉,結果返回值物件會被拷貝兩次。故不到萬不得已,不要輕易返回大尺寸物件。
c++函式的返回值傳遞
c++處理大返回值略有不同,其可能是像c那樣,1次拷貝到棧上的臨時物件裡,然後把臨時物件拷貝到儲存返回值的物件裡。但,有些編譯器會進行返回值優化rvo(return value optimization),這樣,物件拷貝會減少一次,即沒有臨時物件temp了,直接拷貝到主調函式的相應物件中。
函式呼叫時發生了什麼
我們下面就來 一下高階語言中函式的呼叫和遞迴等性質是怎樣通過系統棧巧妙實現的。請看如下 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 這段...
函式呼叫時發生了什麼?
我們以如下 示例,描述函式呼叫過程中,棧的操作過程 voidf intg int x 每次函式呼叫,作業系統都會在棧中建立乙個棧幀 stack frame 正在執行的函式引數 區域性變數 申請的記憶體位址等都在當前棧幀中,也就是堆疊的頂部棧幀中。如下圖所示 當 f 函式執行的時候,f 函式就在棧頂,...
函式呼叫的時候棧發生了什麼?
問題分析 本文分析的問題是函式的棧呼叫機理。先說結論 所謂的暫存器入棧 實際上是指的一組暫存器入棧。因為在新呼叫的函式中,這些暫存器仍然會被用到,為了退出呼叫函式後能恢復狀態,凡是有可能被修改的暫存器都要入棧。出棧順序和入棧順序相反。這個過程由編譯器維護。在現在普遍應用的單指令流,單資料流計算機上,...