c基礎 函式呼叫規則詳解

2021-08-09 07:18:36 字數 3249 閱讀 2185

在引數傳遞中,有兩個重要的問題必須要明確說明:

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   // 清理堆疊

在編譯時,此方式的函式被翻譯成:_function

3. fastcall

fastcall 按照名字上理解就可以知道,它是一種快速呼叫方式。此方式的函式的第乙個和第二個dword引數通過ecx和edx傳遞,

後面的引數從右向左的順序壓入棧。

被呼叫函式清理堆疊。

函式名修個規則同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 test1(char *var1,unsigned long)-----「?test1@@yghpadk@z」

void test2() -----「?test2@@ygxxz」

__cdecl呼叫約定:

規則同上面的_stdcall呼叫約定,只是參數列的開始標識由上面的「@@yg」變為「@@ya」。

__fastcall呼叫約定:

規則同上面的_stdcall呼叫約定,只是參數列的開始標識由上面的「@@yg」變為「@@yi」。

vc++對函式的省缺宣告是"__cedcl",將只能被c/c++呼叫。

c 函式呼叫規則

呼叫規則主要是指函式被呼叫的方式,常見的有 stdcall,fastcall,pascal等規則。不同的規則在引數壓入堆疊的順序是不同的,同時在有呼叫者清理壓入堆疊的引數還是由被呼叫者清理壓入堆疊的引數上也是不同的。一般來說,如果你沒有顯式的說明呼叫規則的話,編譯器會統一按照 cdecl來處理 wi...

函式呼叫規則

2018年4月12日星期四 函式呼叫規則 函式呼叫過程 可在vc上逐步除錯檢視暫存器,記憶體的變化情況 1.一些暫存器的用法 ebp eip esi push pop 影響esp的值 eip 1.放的是當前執行 當前指令 的位址 2.call,ret 從當前函式返回 這倆指令將會影響eip的值 br...

C,C ,VC 函式呼叫規則

以下內容 於網路 1 stdcall是pascal程式的預設呼叫方式,通常用於win32 api中,函式採用從右到左的壓棧方式,自己在退出時清空堆疊。vc將函式編譯後會在函式名前面加上下劃線字首,在函式名後加上 和引數的位元組數。2 c呼叫約定 即用 cdecl關鍵字說明 按從右至左的順序壓引數入棧...