函式呼叫約定常見的函式呼叫約定[5]:cdecl,stdcall,fastcall,thiscall,naked call1.__cdecl(c呼叫約定.the c default calling convention)c/c++ 預設呼叫方式mfc呼叫約定(vs6:project settings->c/c++ calling convention:)
壓棧順序:函式引數從右到左
引數棧維護:由呼叫函式把引數彈出棧,傳送引數的記憶體棧由呼叫函式來維護
函式修飾名約定: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...