呼叫函式時,計算機常用棧來儲存傳遞給函式的引數。
棧是一種先進後出的資料結構,棧有乙個儲存區、乙個棧頂指標。棧頂指標指向堆疊中第乙個可用的資料項(被稱為棧頂)。使用者可以在棧頂上方向棧中加入資料,這個操作被稱為壓棧(push),壓棧以後,棧頂自動變成新加入資料項的位置,棧頂指標也隨之修改。使用者也可以從堆疊中取走棧頂,稱為彈出棧(pop),彈出棧後,棧頂下的乙個元素變成棧頂,棧頂指標隨之修改。函式呼叫時,呼叫者依次把引數壓棧,然後呼叫函式,函式被呼叫以後,在堆疊中取得資料,並進行計算。函式計算結束以後,或者呼叫者、或者函式本身修改堆疊,使堆疊恢復原裝。
在引數傳遞中,有兩個重要的問題必須要明確說明:
1. 當引數個數多於乙個時,按照什麼順序把引數壓入堆疊;
2. 函式呼叫後,由誰來把堆疊恢復原狀。
在高階語言中,就是通過函式的呼叫方式來說明這兩個問題的。常見的呼叫方式有:
stdcall
cdecl
fastcall
thiscall
thiscall
naked call
下面就分別介紹這幾種呼叫方式:
1. stdcall
stdcall呼叫方式又被稱為pascal呼叫方式。在microsoft c++系列的c/c++編譯器中,使用pascal巨集,winapi巨集和callback巨集來指定函式的呼叫方式為stdcall。
stdcall呼叫方式的函式宣告為:
int _stdcall function(int a, int b);
stdcall的呼叫方式意味著:
(1) 引數從右向左一次壓入堆疊
(2) 由被呼叫函式自己來恢復堆疊
(3) 函式名自動加前導下劃線,後面緊跟著乙個@,其後緊跟著引數的尺寸
上面那個函式翻譯成組合語言將變成:
push b 先壓入第二個引數
push a 再壓入第乙個引數
call function 呼叫函式
在編譯時,此函式的名字被翻譯為_function@8
2. cdecl
cdecl呼叫方式又稱為c呼叫方式,是c語言預設的呼叫方式,它的語法為:
int function(int a, int b) // 不加修飾符就是c呼叫方式
int _cdecl function(int a, int b) // 明確指定用c呼叫方式
cdecl的呼叫方式決定了:
(1) 引數從右向左依次壓入堆疊
(2) 由呼叫者恢復堆疊
(3) 函式名自動加前導下劃線
由於是由呼叫者來恢復堆疊,因此c呼叫方式允許函式的引數個數是不固定的,這是c語言的一大特色。
此方式的函式被翻譯為:
push b // 先壓入第二個引數
push a // 在壓入第乙個引數
call funtion // 呼叫函式
add esp, 8 www.cppcns.com; // 清理堆疊
在編譯時,此方式的函式被翻譯成:_function
3. fastcall
fastcall 按照名字上理解就可以知道,它是一種快速呼叫方式。此方式的函式的第乙個和第二個dword引數通過ecx和edx傳遞,
後面www.cppcns.com的引數從右向左的順序壓入棧。
被呼叫函式清理堆疊。
函式名修個規則同stdcall
其宣告語法為:
int fastcall function(int a, int b);
4. thiscall
thiscall 呼叫方式是唯一一種不能顯示指定的修飾符。它是c++類成員函式預設的呼叫方式。由於成員函式呼叫還有乙個this指標,因此必須用這種特殊的呼叫方式。
thiscall呼叫方式意味著:
引數從右向左壓入棧。
如果引數個數確定,this指標通過ecx傳遞給被呼叫者;如果引數個數不確定,this指標在所有引數壓入棧後被壓入棧。
引數個數不定的,由呼叫者清理堆疊,否則由函式自己清理堆疊。
可以看到,對於引數個數固定的情況,它類似於stdcall,不定時則類似於cdecl。
5. naked call
是一種比較少見的呼叫方式,一般高階程式語言中不常見。
函式的宣告呼叫方式和實際呼叫方式必須一致,必然編譯器會產生混亂。
函式名字修改規則:
1. c編譯時函式名修飾約定規則:
__stdcall呼叫約定在輸出函式名前加上乙個下劃線字首,後面加上乙個「@」符號和其引數的位元組數,格式為_function@8。
__cdecl呼叫約定僅在輸出函式名前加上乙個下劃線字首,格式為_function。
__fastcall呼叫約定在輸出函式名前加上乙個「@」符號,後面也是乙個「@」符號和其引數的位元組數,格式為@function@8。
它們均不改變輸出函式名中的字元大小寫,這和pascal呼叫約定不同,pascal約定輸出的函式名無任何修飾且全部大寫。
2. c++編譯時函式名修飾約定規則:
__stdcall呼叫約定:
(1)以「?」標識函式名的開始,後跟函式名;
(2)函式名後面以「@@yg」標識參數列的開始,後跟參數列;
(3)參數列以代號表示:
x--void ,
d--char,
e--unsigned char,
f--short,
h--int,
i--unsigned int,
j--long,
k--unsigned long,
m--float,
n--double,
_n--bool,
pa--表示指標,後面的代號表明指標型別,如果相同型別的指標連續出現,以「0」代替,乙個「0」代
表一次重複;
(4)參數列的第一項為該函式的返回值型別,其後依次為引數的資料型別,指標標識在其所指資料型別前;
(5)參數列後以「@z」標識整個名字的結束,如果該函式無引數,則以「z」標識結束。
其格式為「?functionname@@yg*****@z」或「?functionname@@yg*xz」,例如
int teswww.cppcns.comt1(char *var1,unsigned long)-----「?test1@@yghpadk@z」
void test2() -----「?test2@@ygxxz」
__cdecl呼叫約定:
規則同上面的_stdcall呼叫約定,只是參數列的開始標識由上面的「@@yg」變為「@@ya」。
__fastcall呼叫約定:
規則同上面的_stdcall呼叫約定,只是參數列的開始標識由上面的「@@yg」變為「@@yi」。
vc++對函式的省缺宣告是"__cedcl",將只能被c/c++調程式設計客棧用。
本文標題: c/c++函式呼叫的幾種方式總結
本文位址: /ruanjian/c/102973.html
C C 函式呼叫的幾種方式總結
目錄 1 為什麼需要指定函式呼叫方式?2 常見的函式呼叫方式 2.1 stdcall 2.2 cdecl 2.3 fastcall 2.4 thiscall 呼叫函式時,計算機常用棧來儲存傳遞給函式的引數。在引數傳遞中,有兩個重要的問題必須要明確說明 1.當引數個數多於乙個時,按照什麼順序把引數壓入...
C C 函式呼叫的幾種方式
我們知道,呼叫函式時,計算機常用棧來存放函式執行需要的引數,由於棧的空間大小是有限的,在 windows 下棧是向低位址擴充套件的資料結構,是一塊連續的記憶體區域。這句話的意思是棧頂的位址和棧的最大容量是系統預先規定好的,windows下棧的大小是2m 也有的說是1m 如果申請的空間超過棧的剩餘空間...
C C 函式呼叫方式
cdecl 是c declaration的縮寫 declaration,宣告 表示c語言預設的函式呼叫方法 所有引數從右到左依次入棧,這些引數由呼叫者清除,稱為手動清棧。被呼叫函式不會要求呼叫者傳遞多少引數,呼叫者傳遞過多或者過少的引數,甚至完全不同的引數都不會產生編譯階段的錯誤。stdcall 是...