您好,登錄后才能下訂單哦!
這篇文章將為大家詳細(xì)講解有關(guān)C++語(yǔ)言常見(jiàn)函數(shù)調(diào)用約定有哪些,小編覺(jué)得挺實(shí)用的,因此分享給大家做個(gè)參考,希望大家閱讀完這篇文章后可以有所收獲。
C /C++開(kāi)發(fā)中,程序編譯沒(méi)有問(wèn)題,但鏈接的時(shí)候報(bào)告函數(shù)不存在,或程序編譯和鏈接都沒(méi)有錯(cuò)誤,但只要調(diào)用庫(kù)中的函數(shù)就會(huì)出現(xiàn)堆棧異常等現(xiàn)象。上述現(xiàn)象出現(xiàn)在C和C++的代碼混合使用的情況下或在C++程序中使用第三方庫(kù)(非C++語(yǔ)言開(kāi)發(fā))的情況下,原因是函數(shù)調(diào)用約定(Calling Convention)和函數(shù)名修飾(Decorated Name)規(guī)則導(dǎo)致的。函數(shù)調(diào)用約定決定函數(shù)參數(shù)入棧的順序,以及由調(diào)用者函數(shù)還是被調(diào)用函數(shù)負(fù)責(zé)清除棧中的參數(shù)等問(wèn)題,而函數(shù)名修飾規(guī)則決定編譯器使用何種名字修飾方式來(lái)區(qū)分不同的函數(shù),如果函數(shù)之間的調(diào)用約定不匹配或者名字修飾不匹配就會(huì)產(chǎn)生以上的問(wèn)題。
C++語(yǔ)言中的函數(shù)調(diào)用約定主要針對(duì)三個(gè)問(wèn)題:
A、函數(shù)參數(shù)的入棧順序
B、清理?xiàng)5闹黧w(負(fù)責(zé)清理?xiàng)5闹黧w:函數(shù)自身還是調(diào)用函數(shù)者)
C、函數(shù)名稱重整
調(diào)用約定主要是指函數(shù)被調(diào)用的方式,C++語(yǔ)言的函數(shù)調(diào)用約定主要有stdcall,fastcall,pascal,cdecl,thiscall等約定。
在C++中,為了允許操作符重載和函數(shù)重載,C++編譯器通常按照某種規(guī)則改寫(xiě)每一個(gè)入口點(diǎn)的符號(hào)名,以便允許同一個(gè)名字(具有不同的參數(shù)類型或者是不同的作用域)有多個(gè)用法,而不會(huì)打破現(xiàn)有的基于C的鏈接器。這項(xiàng)技術(shù)通常被稱為名稱改編(Name Mangling)或者名稱修飾(Name Decoration)。C++編譯器廠商通常選擇自己的名稱修飾方案。
__stdcall
是StandardCall的縮寫(xiě),是C++的標(biāo)準(zhǔn)調(diào)用方式。__stdcall
調(diào)用約定的規(guī)則如下:
A、所有參數(shù)從右到左依次入棧,如果是調(diào)用類成員的話,最后一個(gè)入棧的是this指針。
B、被調(diào)用函數(shù)自動(dòng)清理堆棧,返回值在EAX。
C、函數(shù)修飾名約定:VC將函數(shù)編譯后會(huì)在函數(shù)名前面加上下劃線前綴,在函數(shù)名后加上"@"和參數(shù)的字節(jié)數(shù)。
__cdecl
是C DECLaration的縮寫(xiě)(declaration,聲明),表示C語(yǔ)言默認(rèn)的函數(shù)調(diào)用方法。__cdecl
調(diào)用約定規(guī)則如下:
A、所有參數(shù)從右到左依次入棧
B、所有參數(shù)由調(diào)用者清除,稱為手動(dòng)清棧。返回值在EAX中
C、函數(shù)修飾名約定:VC將函數(shù)編譯后會(huì)在函數(shù)名前面加上下劃線前綴
由于由調(diào)用者清理?xiàng)?,所以允許可變參數(shù)函數(shù)存在,如int sprintf(char buffer,const char format,...)。
__fastcall
是快速調(diào)用約定,通過(guò)寄存器來(lái)傳送參數(shù)。__fastcall
調(diào)用約定的規(guī)則如下:
A、用ECX和EDX傳送前兩個(gè)雙字(DWORD)或更小的參數(shù),剩下的參數(shù)仍舊自右向左壓棧傳送
B、被調(diào)用函數(shù)在返回前清理傳送參數(shù)的內(nèi)存棧 ,返回值在EAX中
C、函數(shù)修飾名約定:VC將函數(shù)編譯后會(huì)在函數(shù)名前面加上"@"前綴,在函數(shù)名后加上"@"和參數(shù)的字節(jié)數(shù) 。
thiscall是唯一一個(gè)不能明確指明的函數(shù)修飾符,thiscall只能用于C++類成員函數(shù)的調(diào)用,同時(shí)thiscall也是C++成員函數(shù)缺省的調(diào)用約定。由于成員函數(shù)調(diào)用還有一個(gè)this指針,因此必須特殊處理。
thiscall調(diào)用約定如下:
A、采用桟傳遞參數(shù),參數(shù)從右向左入棧。如果參數(shù)個(gè)數(shù)確定,this指針通過(guò)ECX傳遞給被調(diào)用者;如果參數(shù)個(gè)數(shù)不確定,this指針在所有參數(shù)壓棧后被壓入堆棧。
B、對(duì)參數(shù)個(gè)數(shù)不定的,調(diào)用者清理堆棧,否則由被調(diào)函數(shù)清理堆棧
thiscall 不是關(guān)鍵字,程序員不能使用。
__pascal
語(yǔ)言的調(diào)用約定,跟 __stdcall
一樣,參數(shù)按照從右至左的方式入棧,函數(shù)自身清理堆棧,返回值在EAX中。VC 中已經(jīng)廢棄,建議使用 stdcall 代替。
關(guān)于“C++語(yǔ)言常見(jiàn)函數(shù)調(diào)用約定有哪些”這篇文章就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,使各位可以學(xué)到更多知識(shí),如果覺(jué)得文章不錯(cuò),請(qǐng)把它分享出去讓更多的人看到。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。