__cdecl,__fastcall, __stdcall 什麼差別?
函數參數入棧的方式
---------------------------------------------------------------
在函數調用過程中,會使用堆棧,這三個表示不同的堆棧調用方式和釋放方式。
比如說__cdecl,它是标準的c方法的堆棧調用方式,就是在函數調用時的參數壓入堆棧是與函數的聲明順序相反的,其它兩個可以看MSDN,不過這個對我們程式設計沒有太大的作用
---------------------------------------------------------------
調用約定
調用約定(Calling convention)決定以下内容:函數參數的壓棧順序,由調用者還是被調用者把參數彈出棧,以及産生函數修飾名的方法。MFC支援以下調用約定:
_cdecl
按從右至左的順序壓參數入棧,由調用者把參數彈出棧。對于“C”函數或者變量,修飾名是在函數名前加下劃線。對于“C++”函數,有所不同。
如函數void test(void)的修飾名是_test;對于不屬于一個類的“C++”全局函數,修飾名是?test@@ZAXXZ。
這是MFC預設調用約定。由于是調用者負責把參數彈出棧,是以可以給函數定義個數不定的參數,如printf函數。
_stdcall
按從右至左的順序壓參數入棧,由被調用者把參數彈出棧。對于“C”函數或者變量,修飾名以下劃線為字首,然後是函數名,然後是符号“@”及參數的位元組數,如函數int func(int a, double b)的修飾名是[email protected]。對于“C++”函數,則有所不同。
所有的Win32 API函數都遵循該約定。
_fastcall
頭兩個DWORD類型或者占更少位元組的參數被放入ECX和EDX寄存器,其他剩下的參數按從右到左的順序壓入棧。由被調用者把參數彈出棧,對于“C”函數或者變量,修飾名以“@”為字首,然後是函數名,接着是符号“@”及參數的位元組數,如函數int func(int a, double b)的修飾名是@[email protected]。對于“C++”函數,有所不同。
未來的編譯器可能使用不同的寄存器來存放參數。
thiscall
僅僅應用于“C++”成員函數。this指針存放于CX寄存器,參數從右到左壓棧。thiscall不是關鍵詞,是以不能被程式員指定。
naked call
采用1-4的調用約定時,如果必要的話,進入函數時編譯器會産生代碼來儲存ESI,EDI,EBX,EBP寄存器,退出函數時則産生代碼恢複這些寄存器的内容。naked call不産生這樣的代碼。
naked call不是類型修飾符,故必須和_declspec共同使用,如下:
__declspec( naked ) int func( formal_parameters )
{
// Function body
}
過時的調用約定
原來的一些調用約定可以不再使用。它們被定義成調用約定_stdcall或者_cdecl。例如:
#define CALLBACK __stdcall
#define WINAPI __stdcall
#define WINAPIV __cdecl
#define APIENTRY WINAPI
#define APIPRIVATE __stdcall
#define PASCAL __stdcall