調用約定(Calling Convention) 是計算機編程中一個比較底層的設計,它主要涉及:
函數參數通過寄存器傳遞還是棧? 函數參數從左到右還是從右到左壓棧? 是否支持可變參數函數(vararg function or variadic function)。 是否需要函數原型? 調用者(caller)還是被調用者(called or callee)清理堆棧?在C和C++中有幾種調用約定:__cdecl, __stdcall, __fastcall, __thiscall, __clrcall, __vectorcall。下面對比下幾種調用約定。
C Declaration Calling Convention,C聲明調用約定。它是C和C++默認的調用約定。特點:
堆棧由調用者清除(手動清除)。 參數從右到左壓棧。 支持可變參數(函數自己並不知道自己有多少個參數,因此需要調用者來清除)。 編譯後函數名改編為:“_函數名”。如_funcname。Standard Calling Convention,標准調用約定。特點:
調用者清除堆棧。 參數從右到坐壓棧(和__cdecl一樣),如果調用類的成員函數,最後壓入this指針。 需要一個函數原型,不支持變參函數。 函數名改編:“_函數名@參數字節大小十進制”。如_funcname@8。Fast Calling Convention,快速調用約定。通過使用寄存器解決效率問題。特點:
函數參數部分通過寄存器傳遞,函數中最左的兩個DWORD(寄存器大小是雙字)或者更小的參數,通過寄存器傳遞。剩下的從右到左堆棧傳遞。 函數名改編:“@函數名@函數參數字節大小十進制”。 返回方式同__stdcall。主要用於解決this指針問題,使用寄存器傳遞this指針。返回方式同__stdcall.
__clrcall是C++ .Net裡面的。
要求盡可能在寄存器中傳遞參數。函數名改編為”@@函數名@參數字節數十進制”。這是微軟自己添加的標准。
除了__cdecl(以及__clrcall),其他的都是被調用者清除堆棧。