調用約定是指程序在函數調用時傳遞參數和獲取返回值所采用的方法:通過寄存器、或通過棧、或者是兩者的混合。用於指定Calling Convention的修飾符主要有:__cdecl,__stdcall,__fastcall等。調用約定可以通過工程設置:Setting...\C/C++ \Advanced\CallingConvention 項進行選擇,缺省狀態為__cdecl。它們決定以下內容:
1)、函數參數的壓棧順序,
2)、由調用者還是被調用者把參數彈出棧,
3)、以及產生函數修飾名的方法。
它們的各自特征如下(以VS2005工具為例):
1.1、參數按從右到左的順序傳遞,放於棧中
1.2、棧的清空由主調函數完成
1.3、在生成的匯編代碼中,函數名以下劃線_ 開頭
編譯選項:/Gd, 對於變參函數,如printf,只能用這種方式
2.1、函數的參數自右向左通過棧傳遞
2.2、被調用的函數在返回前清理傳送參數的內存棧
2.3、在生成的匯編代碼中,函數名以下劃線_ 開頭,以@和所有參數所占用的字節數結尾。如call _sumExample@8
編譯選項:/Gz,Win32程序中的WINAPI即是__stdcall:#define WINAPI __stdcall,由於棧是由被調函數自己清空,其產生的執行代碼要小於__cdecl方式所產生的代碼。
3.1、前兩個參數要求不超過32bits,分別放入ECX和EDX,其余參數按從右到左的順序傳遞,放於棧中
3.2、參數由被調函數彈出棧
3.3、在生成的匯編代碼中,函數名以@開頭,以@和所有參數所占用的字節數結尾
編譯選項:/Gr
除這三種之外,還有Thiscall,但它僅用於C++中類的成員函數:
1、參數按從右到左的順序傳遞,放於棧中。this放於ECX中
2、棧的清空有被調函數完成
這是C++中類成員函數默認的calling convention。但如果類的成員函數包含可變參數,那該函數的調用約定則是__cdecl。
C 和C++ 對應不同的調用約定,產生的修飾符也各不相同,對於函數test(void)如下:
調用約定
extern "C" 或 .c 文件
.cpp、.cxx 或 /TP
__cdecl
_test
?test@@ZAXXZ
__fastcall
@test@0
?test@@YIXXZ
__stdcall
_test@0
?test@@YGXXZ
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",例如
intTest1(char *var1,unsigned long)----"?Test1@@YGHPADK@Z"
voidTest2()-----“?Test2@@YGXXZ”
__cdecl調用約定:
規則同上面的_stdcall調用約定,只是參數表的開始標識由上面的"@@YG"變為"@@YA"。
__fastcall調用約定:
規則同上面的_stdcall調用約定,只是參數表的開始標識由上面的"@@YG"變為"@@YI"。
VC++對函數的省缺聲明是"__cedcl",將只能被C/C++調用。
附:一個DLL在內存中只有一個實例
DLL程序和調用其輸出函數的程序的關系:
1)、DLL與進程、線程之間的關系
DLL模塊被映射到調用它的進程的虛擬地址空間。
DLL使用的內存從調用進程的虛擬地址空間分配,只能被該進程的線程所訪問。
DLL的句柄可以被調用進程使用;調用進程的句柄可以被DLL使用。
DLLDLL可以有自己的數據段,但沒有自己的堆棧,使用調用進程的棧,與調用它的應用程序相同的堆棧模式。
2)、關於共享數據段
DLL定義的全局變量可以被調用進程訪問;DLL可以訪問調用進程的全局數據。使用同一DLL的每一個進程都有自己的DLL全局變量實例。如果多個線程並發訪問同一變量,則需要使用同步機制;對一個DLL的變量,如果希望每個使用DLL的線程都有自己的值,則應該使用線程局部存儲(TLS,Thread LocalStrorage)