1、(Microsoft Specific)__stdcall主要指明了恢複堆棧的規則:在主調用函數中負責壓棧,在被調用函數中負責彈出堆棧中的參數,并且負責恢複堆棧。<?xml:namespace prefix = o />
The __stdcall calling convention is used to call Win32 API functions. The callee(被調用者) cleans the stack, so the compiler makes vararg functions __cdecl. Functions that use this calling convention require a function prototype. The following list shows the implementation of this calling convention.
Element
Implementation
Argument-passing order
Right to left.
Argument-passing convention
By value, unless a pointer or reference type is passed.
Stack-maintenance responsibility
Called function pops its own arguments from the stack.
Name-decoration convention
An underscore (_) is prefixed to the name. The name is followed by the at sign (@) followed by the number of bytes (in decimal) in the argument list. Therefore, the function declared as int func( int a, double b ) is decorated as follows: _func@12
Case-translation convention
None
The /Gz compiler option specifies __stdcall for all functions not explicitly declared with a different calling convention.
Functions declared using the __stdcall modifier return values the same way as functions declared using __cdecl.
Example
In the following example, use of __stdcall results in all WINAPI function types being handled as a standard call:
// Example of the __stdcall keyword
#define WINAPI __stdcall
__cdecl和__stdcall最大的差別在于:使用__stdcall調用方式的函數在傳回以前要把傳給它的參數彈出堆棧,而使用__cdecl調用方式的函數可以直接傳回,由調用它的函數來将用過的參數彈出堆棧。
2、調用約定:
__cdecl預設
是BorlandC++的預設的C格式命名約定,它在辨別符前加一下劃線,以保留它原來所有的全程辨別符。參數按最右邊參數優先的原則傳遞給棧,然後清棧。
extern"C "bool __cdecl TestFunction();
在def檔案中顯示為
TestFunction @1
注釋:@1表示函數的順序數,将在“使用别名”時使用。
__pascalPascal格式
這時函數名全部變成大寫,第一個參數先壓棧,然後清棧。
TESTFUNCTION @1 //deffile
__stdcall标準調用
最後一個參數先壓棧,然後清棧。
TestFunction @1 //deffile
__fastcall把參數傳遞給寄存器
第一個參數先壓棧,然後清棧。
@TestFunction @1 //deffile
3、在VC中!
__cdecl無特征,隻輸出函數名
__stdcall的函數輸出前會帶一 "_"字尾帶 "@nn "
__fastcall函數輸出前帶一 "@ "字尾帶 "@nn
4、調用約定
1)__stdcall調用約定相當于16位動态庫中經常使用的PASCAL調用約定。在32位的VC++5.0中PASCAL調用約定不再被支援(實際上它已被定義為__stdcall。除了__pascal外,__fortran和__syscall也不被支援),取而代之的是__stdcall調用約定。兩者實質上是一緻的,即函數的參數自右向左通過棧傳遞,被調用的函數在傳回前清理傳送參數的記憶體棧,但不同的是函數名的修飾部分(關于函數名的修飾部分在後面将詳細說明)。
__stdcall是Pascal程式的預設調用方式,通常用于Win32 Api中,函數采用從右到左的壓棧方式,自己在退出時清空堆棧。VC将函數編譯後會在函數名前面加上下劃線字首,在函數名後加上 "@ "和參數的位元組數。
2) C調用約定(即用__cdecl關鍵字說明)按從右至左的順序壓參數入棧,由調用者把參數彈出棧。對于傳送參數的記憶體棧是由調用者來維護的(正因為如此,實作可變參數的函數隻能使用該調用約定)。另外,在函數名修飾約定方面也有所不同。
_cdecl是C和C++程式的預設調用方式。每一個調用它的函數都包含清空堆棧的代碼,是以産生的可執行檔案大小會比調用_stdcall函數的大。函數采用從右到左的壓棧方式。VC将函數編譯後會在函數名前面加上下劃線字首,是MFC預設調用約定。
3) __fastcall調用約定是“人”如其名,它的主要特點就是快,因為它是通過寄存器來傳送參數的(實際上,它用ECX和EDX傳送前兩個雙字(DWORD)或更小的參數,剩下的參數仍舊自右向左壓棧傳送,被調用的函數在傳回前清理傳送參數的記憶體棧),在函數名修飾約定方面,它和前兩者均不同。
_fastcall方式的函數采用寄存器傳遞參數,VC将函數編譯後會在函數名前面加上 "@ "字首,在函數名後加上 "@ "和參數的位元組數。
4) thiscall僅僅應用于“C++”成員函數。this指針存放于CX寄存器,參數從右到左壓。thiscall不是關鍵詞,是以不能被程式員指定。
5)naked call采用1-4的調用約定時,如果必要的話,進入函數時編譯器會産生代碼來儲存ESI,EDI,EBX,EBP寄存器,退出函數時則産生代碼恢複這些寄存器的内容。naked call不産生這樣的代碼。naked call不是類型修飾符,故必須和_declspec共同使用。
關鍵字__stdcall、__cdecl和__fastcall可以直接加在要輸出的函數前,也可以在編譯環境的Setting...\C/C++ \Code Generation項選擇。當加在輸出函數前的關鍵字與編譯環境中的選擇不同時,直接加在輸出函數前的關鍵字有效。它們對應的指令行參數分别為/Gz、 /Gd和/Gr。預設狀态為/Gd,即__cdecl。
要完全模仿PASCAL調用約定首先必須使用__stdcall調用約定,至于函數名修飾約定,可以通過其它方法模仿。還有一個值得一提的是WINAPI 宏,Windows.h支援該宏,它可以将出函數翻譯成适當的調用約定,在WIN32中,它被定義為__stdcall。使用WINAPI宏可以建立自己的APIs。
參考
[2] MSDN