cdecl、pascal、stdcall、fastcall
Directive Parameter order Clean-up Passes parameters in registers?
register Left-to-right Routine Yes
pascal Left-to-right Routine No
cdecl Right-to-left Caller No
stdcall Right-to-left Routine No
safecall Right-to-left Routine No
調用約定 壓參數入棧順序 把參數彈出棧者 函數修飾名
(Calling convention)
--------------------------------------------------------------------------------------------------------
__cdecl 右->左 調用者 _function
__fastcall 右->左 被調用者 @function@nnn
__stdcall 右->左 被調用者 _function@nnn
__pascal 左->右 被調用者 _function@nnn
-----------------------------------------------------------------------------------------------------------
__cdecl是C/C++和MFC程序默認使用的調用約定,也可以在函數聲明時加上__cdecl關鍵字來手工指定。采用__cdecl約定時,函數參數按照從右到左的順序入棧,并且由調用函數者把參數彈出棧以清理堆棧。因此,實現可變參數的函數只能使用該調用約定。由于每一個使用__cdecl約定的函數都要包含清理堆棧的代碼,所以產生的可執行文件大小會比較大。__cdecl可以寫成_cdecl。
__stdcall調用約定用于調用Win32 API函數。采用__stdcal約定時,函數參數按照從右到左的順序入棧,被調用的函數在返回前清理傳送參數的棧,函數參數個數固定。由于函數體本身知道傳進來的參數個數,因此被調用的函數可以在返回前用一條ret n指令直接清理傳遞參數的堆棧。__stdcall可以寫成_stdcall。
__fastcall約定用于對性能要求非常高的場合。__fastcall約定將函數的從左邊開始的兩個大小不大于4個字節(DWORD)的參數分別放在ECX和EDX寄存器,其余的參數仍舊自右向左壓棧傳送,被調用的函數在返回前清理傳送參數的堆棧。__fastcall可以寫成_fastcall。
·特別說明
1. 在默認情況下,采用__cdecl方式,因此可以省略.
2. WINAPI一般用于修飾動態鏈接庫中導出函數
3. CALLBACK僅用于修飾回調函數
便于更好理解, 看下面例子(函數調用的過程以匯編代碼表示):
void cdecl fun1(int x,int y);
void stdcall fun2(int x,int y);
void pascal fun3(int x,int y);
****************************************
void cdecl fun1(int x,int y);
fun1(x,y);
調用 fun1 的匯編代碼
push y
push x
call fun1
add sp,sizeof(x)+sizeof(y) ;跳過參數區(x,y)
fun1 的匯編代碼:
fun1 proc
push bp
mov bp,sp
……
…
pop bp
ret ;返回,但不跳過參數區
fun1 endp
****************************************
void stdcall fun2(int x,int y);
fun2(x,y);
調用 fun2 的匯編代碼
push y
push x
call fun2
fun2 的匯編代碼:
fun2 proc
push bp
mov bp,sp
……
…
pop bp
ret sizeof(x)+sizeof(y) ;返回并跳過參數區(x,y)
fun2 endp
*****************************************
void pascal fun3(int x,int y);
fun3(x,y);
調用 fun3 的匯編代碼
push x
push y
call fun3
fun3 的匯編代碼:
fun3 proc
push bp
mov bp,sp
……
…
pop bp
ret sizeof(x)+sizeof(y) ;返回并跳過參數區(x,y)
fun3 endp