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