C /C++開發中,程序編譯沒有問題,但連接的時候報告函數不存在,或程序編譯和連接都沒有錯誤,但只要調用庫中的函數就會出現堆棧異常等現象。上述現象出如今C和C++的代碼混合使用的狀況下或在C++程序中使用第三方庫(非C++語言開發)的狀況下,緣由是函數調用約定(Calling Convention)和函數名修飾(Decorated Name)規則致使的。函數調用約定決定函數參數入棧的順序,以及由調用者函數仍是被調用函數負責清除棧中的參數等問題,而函數名修飾規則決定編譯器使用何種名字修飾方式來區分不一樣的函數,若是函數之間的調用約定不匹配或者名字修飾不匹配就會產生以上的問題。
C++語言中的函數調用約定主要針對三個問題:
A、函數參數的入棧順序
B、清理棧的主體(負責清理棧的主體:函數自身仍是調用函數者)
C、函數名稱重整
調用約定主要是指函數被調用的方式,C++語言的函數調用約定主要有stdcall,fastcall,pascal,cdecl,thiscall等約定。
在C++中,爲了容許操做符重載和函數重載,C++編譯器一般按照某種規則改寫每個入口點的符號名,以便容許同一個名字(具備不一樣的參數類型或者是不一樣的做用域)有多個用法,而不會打破現有的基於C的連接器。這項技術一般被稱爲名稱改編(Name Mangling)或者名稱修飾(Name Decoration)。C++編譯器廠商一般選擇本身的名稱修飾方案。程序員
__stdcall
是StandardCall的縮寫,是C++的標準調用方式。__stdcall
調用約定的規則以下:
A、全部參數從右到左依次入棧,若是是調用類成員的話,最後一個入棧的是this指針。
B、被調用函數自動清理堆棧,返回值在EAX。
C、函數修飾名約定:VC將函數編譯後會在函數名前面加上下劃線前綴,在函數名後加上"@"和參數的字節數。ide
__cdecl
是C DECLaration的縮寫(declaration,聲明),表示C語言默認的函數調用方法。__cdecl
調用約定規則以下:
A、全部參數從右到左依次入棧
B、全部參數由調用者清除,稱爲手動清棧。返回值在EAX中
C、函數修飾名約定:VC將函數編譯後會在函數名前面加上下劃線前綴
因爲由調用者清理棧,因此容許可變參數函數存在,如int sprintf(char buffer,const char format,...)。函數
__fastcall
是快速調用約定,經過寄存器來傳送參數。__fastcall
調用約定的規則以下:
A、用ECX和EDX傳送前兩個雙字(DWORD)或更小的參數,剩下的參數仍舊自右向左壓棧傳送
B、被調用函數在返回前清理傳送參數的內存棧 ,返回值在EAX中
C、函數修飾名約定:VC將函數編譯後會在函數名前面加上"@"前綴,在函數名後加上"@"和參數的字節數 。學習
thiscall是惟一一個不能明確指明的函數修飾符,thiscall只能用於C++類成員函數的調用,同時thiscall也是C++成員函數缺省的調用約定。因爲成員函數調用還有一個this指針,所以必須特殊處理。
thiscall調用約定以下:
A、採用桟傳遞參數,參數從右向左入棧。若是參數個數肯定,this指針經過ECX傳遞給被調用者;若是參數個數不肯定,this指針在全部參數壓棧後被壓入堆棧。
B、對參數個數不定的,調用者清理堆棧,不然由被調函數清理堆棧
thiscall 不是關鍵字,程序員不能使用。this
__pascal
語言的調用約定,跟 __stdcall
同樣,參數按照從右至左的方式入棧,函數自身清理堆棧,返回值在EAX中。VC 中已經廢棄,建議使用 stdcall 代替。指針