C C 函式呼叫約定

2021-08-18 17:29:38 字數 3846 閱讀 4651

函式呼叫約定常見的函式呼叫約定[5]:cdecl,stdcall,fastcall,thiscall,naked call

mfc呼叫約定(vs6:project settings->c/c++ calling convention:)

1.__cdecl(c呼叫約定.the c default calling convention)c/c++ 預設呼叫方式

壓棧順序:函式引數從右到左

引數棧維護:由呼叫函式把引數彈出棧,傳送引數的記憶體棧由呼叫函式來維護

函式修飾名約定:vc將函式編譯後會在函式名前面加上下劃線字首

每乙個呼叫它的函式都包含清空堆疊的**,所以產生的可執行檔案大小會比呼叫_stdcall函式的大

2.__stdcall(pascal方式清理c方式壓棧,通常用於win32 api中)

壓棧順序:函式引數從右到左的壓棧順序

引數棧維護:被呼叫函式把引數彈出棧(在退出時清空堆疊)

函式修飾名約定:vc將函式編譯後會在函式名前面加上下劃線字首,在函式名後加上」@」和引數的位元組數

ex. vc: int f(void *p) (編譯後)-> _f@4(在外部組合語言裡可以用這個名字引用這個函式)

3.__fastcall(快速呼叫約定,通過暫存器來傳送引數)

壓棧順序:用ecx和edx傳送前兩個雙字(dword)或更小的引數,剩下的引數仍舊自右向左壓棧傳送

引數棧維護:被呼叫函式在返回前清理傳送引數的記憶體棧

函式修飾名約定:vc將函式編譯後會在函式名前面加上」@」字首,在函式名後加上」@」和引數的位元組數

4.thiscall(本身呼叫,僅用於「c++」成員函式)

壓棧順序:this指標存放於cx/ecx暫存器中,引數從右到左的壓棧順序

5.naked call(裸調)

當採用1-4的呼叫約定時,如果必要的話,進入函式時編譯器會產生**來

儲存esi,edi,ebx,ebp暫存器,退出函式時則產生**恢復這些暫存器的內容 (這些**稱作 prolog and epilog code,一般,ebp,esp的儲存是必須的)

naked call不產生這樣的**。nakedcall不是型別修飾符,故必須和_declspec共同使用

#ifndef _dll_h_

#define _dll_h_//防重複定義

#if building_dll

# define dllimport __declspec (dllexport)

#else

# define dllimport __declspec (dllimport)

#endif

dllimport void helloworld (void);

#endif

上面**裡面的_delcspce(dllexport)被定義為巨集,這樣可以提高程式的可讀性.

這個的作用是將函式定義為匯出函式,也就是說這個函式要被包含這個函式的程式之外的程式呼叫.

本語句中就是:void helloword(void):

摘自msdn:在 32 位編譯器版本中,可以使用 __declspec(dllexport) 關鍵字從 dll 匯出資料、

函式、類或類成員函式。__declspec(dllexport) 將匯出指令新增到物件檔案

若要匯出函式,__declspec(dllexport) 關鍵字必須出現在呼叫約定關鍵字的左邊(如果指定了關鍵字)

例如:

__declspec(dllexport) void __cdecl function1(void);

若要匯出類中的所有公共資料成員和成員函式,關鍵字必須出現在類名的左邊,如下所示:

class __declspec(dllexport) cexampleexport : public cobject

; 生成 dll 時,通常建立乙個包含正在匯出的函式原型和/或類的標頭檔案,並將 __declspec(dllexport)

新增到頭檔案中的宣告。若要提高**的可讀性,請為 __declspec(dllexport) 定義乙個巨集並對正在匯出的

每個符號使用該巨集:#define dllexport __declspec( dllexport )

__declspec(dllexport) 將函式名儲存在 dll 的匯出表中。如果希望優化表的大小

附錄》

1, 修飾名(decoration name)

「c」或者「c++」函式在內部(編譯和鏈結)通過修飾名識別。修飾名是編譯器在編譯函式定義或者原

型時生成的字串。有些情況下使用函式的修飾名是必要的,如在模組定義檔案裡頭指定輸出「c++」

過載函式、建構函式、析構函式,又如在彙編**裡呼叫「c」」或「c++」函式等。

修飾名由函式名、類名、呼叫約定、返回型別、引數等共同決定。

2、名字修飾約定隨呼叫約定和編譯種類(c或c++)的不同而變化。

函式名修飾約定隨編譯種類和呼叫約定的不同而不同,下面分別說明。

a、c編譯時函式名修飾約定規則:

__stdcall呼叫約定在輸出函式名前加上乙個下劃線字首,後面加上乙個「@」符號和其引數的位元組數,

格式為_functionname@number。

__cdecl呼叫約定僅在輸出函式名前加上乙個下劃線字首,格式為_functionname。

__fastcall呼叫約定在輸出函式名前加上乙個「@」符號,後面也是乙個「@」符號和其引數的位元組數,

格式為@functionname@number。

它們均不改變輸出函式名中的字元大小寫,這和pascal呼叫約定不同,

pascal約定輸出的函式名無任何修飾且全部大寫。

b、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 C 函式呼叫約定

c c 函式呼叫約定 關於c c 函式呼叫約定,大多數時候並不會影響程式邏輯,但遇到跨語言程式設計時,了解一下還是有好處的。vc 中預設呼叫是 cdecl 方式,windows api 使用 stdcall 呼叫方式,在dll 匯出函式中,為了跟windows api 保持一致,建議使用 stdca...

C C 函式呼叫約定

關於 c c 函式呼叫約定,大多數時候並不會影響程式邏輯,但遇到跨語言程式設計時,了解一下還是有好處的。vc 中預設呼叫是 cdecl 方式,windows api 使用 stdcall 呼叫方式,在 dll 匯出函式中,為了跟 windows api 保持一致,建議使用 stdcall 方式。呼叫...

C C 呼叫約定

c c 函式呼叫約定 在程式設計中,乙個函式完整的執行需要經過編譯鏈結等多個過程,而在每個過程中編譯器都需要為程式提供不同的服務,那麼乙個函式的呼叫執行到底需要幾個過程呢?下面我們先通過乙個函式棧幀的建立看看。define crt secure no warnings 1 include inclu...