日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

函數(shù)調(diào)用約定

 TUBOSS 2014-09-30

函數(shù)調(diào)用約定包括傳遞參數(shù)的順序,誰(shuí)負(fù)責(zé)清理參數(shù)占用的堆棧等,例如 :

  參數(shù)傳遞順序 誰(shuí)負(fù)責(zé)清理參數(shù)占用的堆棧
__pascal 從左到右 調(diào)用者
__stdcall 從右到左 被調(diào)函數(shù)
__cdecl 從右到左 調(diào)用者

調(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. 速度不同: _cdecl更快(代碼更多當(dāng)然意味著運(yùn)行更快,有點(diǎn)像內(nèi)聯(lián)函數(shù))

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)生
   a). 不同代碼大小的原因:如果使用_cdecl的函數(shù)多次調(diào)用同一函數(shù),就要產(chǎn)生多份恢復(fù)碼。
   b). 功能不同的原因:實(shí)現(xiàn)變長(zhǎng)參數(shù)列表。一份恢復(fù)碼只能將一種長(zhǎng)度的參數(shù)表出棧,所以要對(duì)不同長(zhǎng)度的參數(shù)表堆棧恢復(fù),必須要有多份代碼,所以變長(zhǎng)參數(shù)必須有主調(diào)函數(shù)恢復(fù)(所以是_cdecl)。

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。
_cdecl:非DLL的console程序。

 

跨語(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)用約定。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶(hù)發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶(hù) 評(píng)論公約

    類(lèi)似文章 更多