當前位置:才華齋>計算機>C語言>

C/C++函式呼叫的方式有哪些

C語言 閱讀(1.45W)

呼叫函式時,計算機常用棧來儲存傳遞給函式的引數。你知道C/C++函式呼叫的方式有哪些嗎?下面本站小編帶大家一起來看看詳細內容,需要的朋友可以過來參考一下!想了解更多相關資訊請持續關注我們應屆畢業生考試網!

C/C++函式呼叫的方式有哪些

棧是一種先進後出的資料結構,棧有一個儲存區、一個棧頂指標。棧頂指標指向堆疊中第一個可用的資料項(被稱為棧頂)。使用者可以在棧頂上方向棧中加入資料,這個操作被稱為壓棧(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 // 清理堆疊

在編譯時,此方式的函式被翻譯成:_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++呼叫。