C 呼叫約定

2021-08-30 07:14:59 字數 3707 閱讀 7863

__cdecl __fastcall與 __stdcall,三者都是呼叫約定(calling convention),它決定以下內容:1)函式引數的壓棧順序,2)由呼叫者還是被呼叫者把引數彈出棧,3)以及產生函式修飾名的方法。

1、__stdcall呼叫約定:函式的引數自右向左通過棧傳遞,被呼叫的函式在返回前清理傳送引數的記憶體棧,

2、_cdecl是c和c++程式的預設呼叫方式。每乙個呼叫它的函式都包含清空堆疊的**,所以產生的可執行檔案大小會比呼叫_stdcall函式的大。函式採用從右到左的壓棧方式。注意:對於可變引數的成員函式,始終使用__cdecl的轉換方式。

3、__fastcall呼叫約定:它是通過暫存器來傳送引數的(實際上,它用ecx和edx傳送前兩個雙字(dword)或更小的引數,剩下的引數仍舊自右向左壓棧傳送,被呼叫的函式在返回前清理傳送引數的記憶體棧)。

5、naked call採用1-4的呼叫約定時,如果必要的話,進入函式時編譯器會產生**來儲存esi,edi,ebx,ebp暫存器,退出函式時則產生**恢復這些暫存器的內容。naked call不產生這樣的**。naked call不是型別修飾符,故必須和_declspec共同使用。

呼叫約定可以通過工程設定:setting...\c/c++ \code generation項進行選擇,預設狀態為__cdecl。

名字修飾約定:

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

__stdcall呼叫約定在輸出函式名前加上乙個下劃線字首,後面加上乙個"@"符號和其引數的位元組數,格式為_functionname@number,例如:function(int a, int b),其修飾名為:_function@8

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

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

3、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++呼叫.

注意:1、_beginthread需要__cdecl的執行緒函式位址,_beginthreadex和createthread需要__stdcall的執行緒函式位址。

2、一般win32的函式都是__stdcall。而且在windef.h中有如下的定義:

#define callback __stdcall

#define winapi  __stdcall

3、extern "c" _declspec(dllexport) int __cdecl add(int a, int b);

typedef int (__cdecl*funpointer)(int a, int b);

修飾符的書寫順序如上。

4、extern "c"的作用:如果add(int a, int b)是在c語言編譯器編譯,而在c++檔案使用,則需要在c++檔案中宣告:extern "c" add(int a, int b),因為c編譯器和c++編譯器對函式名的解釋不一樣(c++編譯器解釋函式名的時候要考慮函式引數,這樣是了方便函式過載,而在c語言中不存在函式過載的問題),使用extern "c",實質就是告訴c++編譯器,該函式是c庫裡面的函式。如果不使用extern "c"則會出現鏈結錯誤。

一般象如下使用:

#ifdef _cplusplus

#define extern_c extern "c"

#else

#define extern_c extern

#endif

#ifdef _cplusplus

extern "c"

#endif

5、mfc提供了一些巨集,可以使用afx_ext_class來代替__declspec(dllexport),並修飾類名,從而匯出類,afx_api_export來修飾函式,afx_data_export來修飾變數

afx_class_import:__declspec(dllexport)

afx_api_import:__declspec(dllexport)

afx_data_import:__declspec(dllexport)

afx_class_export:__declspec(dllexport)

afx_api_export:__declspec(dllexport)

afx_data_export:__declspec(dllexport)

afx_ext_class:#ifdef _afxext

afx_class_export

#else

afx_class_import

6、dllmain負責初始化(initialization)和結束(termination)工作,每當乙個新的程序或者該程序的新的執行緒訪問dll時,或者訪問dll的每乙個程序或者執行緒不再使用dll或者結束時,都會呼叫dllmain。但是,使用terminateprocess或terminatethread結束程序或者執行緒,不會呼叫dllmain。

7、乙個dll在記憶體中只有乙個例項

dll程式和呼叫其輸出函式的程式的關係:

1)、dll與程序、執行緒之間的關係

dll模組被對映到呼叫它的程序的虛擬位址空間。

dll使用的記憶體從呼叫程序的虛擬位址空間分配,只能被該程序的執行緒所訪問。

dll的控制代碼可以被呼叫程序使用;呼叫程序的控制代碼可以被dll使用。

dlldll可以有自己的資料段,但沒有自己的堆疊,使用呼叫程序的棧,與呼叫它的應用程式相同的堆疊模式。

2)、關於共享資料段

dll定義的全域性變數可以被呼叫程序訪問;dll可以訪問呼叫程序的全域性資料。使用同一dll的每乙個程序都有自己的dll全域性變數例項。如果多個執行緒併發訪問同一變數,則需要使用同步機制;對乙個dll的變數,如果希望每個使用dll的執行緒都有自己的值,則應該使用執行緒區域性儲存(tls,thread local strorage)。

C 呼叫約定和名字約定

c 呼叫約定和名字約定 呼叫約定 cdecl fastcall與 stdcall,三者都是呼叫約定 calling convention 它決定以下內容 1 函式引數的壓棧順序,2 由呼叫者還是被呼叫者把引數彈出棧,3 以及產生函式修飾名的方法。1 stdcall呼叫約定 函式的引數自右向左通過棧傳...

C 呼叫約定和名字約定

呼叫約定是指程式在函式呼叫時傳遞引數和獲取返回值所採用的方法 通過暫存器 或通過棧 或者是兩者的混合。用於指定calling convention的修飾符主要有 cdecl,stdcall,fastcall等。呼叫約定可以通過工程設定 setting.c c advanced callingconv...

C 函式呼叫約定

stdcall是 函式呼叫約定的一種,函式呼叫約定主要約束了兩件事 1.引數傳遞順序 2.呼叫 堆疊由誰 呼叫函式或 被呼叫函式 清理 常見的 函式呼叫約定 stdcall cdecl fastcall thiscall naked call stdcall表示 1.引數從右向左壓入堆疊 2.函式被...