呼叫約定:
__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)。
DLL 中呼叫約定和名稱修飾
呼叫約定 calling convention 是指在程式語言中為了實現函式呼叫而建立的一種協議。這種協議規定了該語言的函式中的引數傳送方式 引數是否可變和由誰來處理堆疊等問題。不同的語言定義了不同的呼叫約定。在c 中,為了允許操作符過載和函式過載,c 編譯器往往按照某種規則改寫每乙個入口點的符號名...
DLL中呼叫約定和名稱修飾
dll中呼叫約定和名稱修飾 一 呼叫約定 calling convention 是指在程式語言中為了實現函式呼叫而建立的一種協議。這種協議規定了該語言的函式中的引數傳送方式 引數是否可變和由誰來處理堆疊等問題。不同的語言定義了不同的呼叫約定。在c 中,為了允許操作符過載和函式過載,c 編譯器往往按照...
DLL中呼叫約定和名稱修飾(二)
thiscall thiscall 呼叫約定是 c 中的非靜態類成員函式的預設呼叫約定。thiscall 只能被編譯器使用,沒有相應的關鍵字,因此不能被程式設計師指定。採用 thiscall 約定時,函式引數按照從右到左的順序入棧,被呼叫的函式在返回前清理傳送引數的棧,只是另外通過 ecx暫存器傳送...