函數(shù)調(diào)用約定包括傳遞參數(shù)的順序,誰負責清理參數(shù)占用的堆棧等,例如 :
調(diào)用函數(shù)的代碼和被調(diào)函數(shù)必須采用相同的函數(shù)的調(diào)用約定,程序才能正常運行。在Windows上,__cdecl是C/C++程序的缺省函數(shù)調(diào)用約定。 在有的cpu上,編譯器會用寄存器傳遞參數(shù),函數(shù)使用的堆棧由被調(diào)函數(shù)分配和釋放。這種調(diào)用約定在行為上和__cdecl有一個共同點:實參和形參數(shù)目不符不會導致堆棧錯誤。 不過,即使用寄存器傳遞參數(shù),編譯器在進入函數(shù)時,還是會將寄存器里的參數(shù)存入堆棧指定位置。參數(shù)和局部變量一樣應該在堆棧中有一席之地。參數(shù)可以被理解為由調(diào)用函數(shù)指定初值的局部變量。 _stdcall與_cdecl的不同 a. 默認支持:VC默認使用_cdecl。所以如果需要使用_stdcall,可采用兩種方法:(1)可以在函數(shù)名前手工添加,只對單一函數(shù)有效 (2)直接修改工程屬性(C/C++ > Advanced > Calling Convention)來一次性配置所有的函數(shù) b. 功能不同: _cdecl可實現(xiàn)變長參數(shù)列表 c. 代碼大?。篲stdcall更小
d.
速度不同:
e.
誰負責恢復堆棧:_cdecl主調(diào)用函數(shù)進行參數(shù)壓棧并且恢復堆棧;_stdcall主調(diào)用函數(shù)進行參數(shù)壓棧,被調(diào)函數(shù)恢復堆棧;這也正是產(chǎn)生 f. 產(chǎn)生的函數(shù)名不同: _stdcall調(diào)用約定在輸出函數(shù)名前加上一個下劃線前綴,后面加上一個“@”符號和其參數(shù)的字節(jié)數(shù),格式為_functionname@number。_cdecl調(diào)用約定僅在輸出函數(shù)名前加上一個下劃線前綴,格式為_functionname。 g. 使用范圍:
_stdcall:通常用于DLL的創(chuàng)建(以支持多語言調(diào)用);此外Win32
API函數(shù)皆用_stdcall(比如MessageBox),所以Win32程序中的自定義函數(shù)也做好使用_stdcall。
跨語言調(diào)用
函數(shù)調(diào)用約定只是“調(diào)用函數(shù)的代碼”和被調(diào)用函數(shù)之間的關系。
假設函數(shù)A是__stdcall,函數(shù)B調(diào)用函數(shù)A。你必須通過函數(shù)聲明告訴編譯器,函數(shù)A是__stdcall。編譯器自然會產(chǎn)生正確的調(diào)用代碼。 如果函數(shù)A是__stdcall。但在引用函數(shù)A的地方,你卻告訴編譯器,函數(shù)A是__cdecl方式,編譯器產(chǎn)生__cdecl方式的代碼,與函數(shù)A的調(diào)用約定不一致,就會發(fā)生錯誤。 以delphi調(diào)用VC函數(shù)為例,delphi的函數(shù)缺省采用__pascal約定,VC的函數(shù)缺省采用__cdecl約定。我們一般將VC的函數(shù)設為__stdcall,例如:
int __stdcall add(int a, int
b);
在delphi中將這個函數(shù)也聲明為__stdcall,就可以調(diào)用了:
function add(a: Integer; b:
Integer): Integer;
stdcall; external ‘a(chǎn).dll’; 因為考慮到可能被其它語言的程序調(diào)用,不少API采用__stdcall的調(diào)用約定。 |
|
來自: TUBOSS > 《函數(shù)調(diào)用約定》