_stdcall 、_cdecl、_fastcal等调用约定
并不是所有的语言都支持_cdcel调用规则,但是都支持_sdtcall调用规则, 假如你用VC做了一个DLL,导出了某些函数,如果你想这个DLL被其他语言也能调用的话,VB.DEPHI.PB..你的把他的调用约定声明为__stdcallwindows api都是_stdcall调用规则,
函数调用约定确定一个程序如何实现一个函数调用及参数如何传递。在单一语言程序中,调用约定几乎总是正确的,这是因为对所有模块总有一个缺省的约定并且头文件会负责调用和被调用程序之间的一致性。在一个混合语言程序中,不同的语言不可能分享同一个头文件。由于调用约定而产生的错误在编译时无法发现,直到程序在运行时(run-time)实现函数调用时才出现并会立即导致应用程序崩溃。
关键字 | 栈的维护者 | 参数传递 | 补充1 | 补充2 |
_cdecl | 调用者 | 参数反序入栈(右-> 左) |
C语言调用约定 C语言默认的函数调用方法 C/C++ 的默认调用函数的规则 |
比较灵活,但是性能比较低(相对_stdcall) |
_stdcall | 被调用者 | 参数反序入栈(右-> 左) |
Pascal语言调用约定 大部分的Windows API都采用Pascal语言调用约定, C++的标准调用方式 |
采用C语言编程的时候,如果要采用这种调用约定, 需要在函数声明的时候加上__stdcall关键字。 不灵活,但性能高(相对_cdecl) |
_fastcall | 被调用者 | 参数先存寄存器,接着入栈 |
快速调用约定 将参数放在寄存器中,以提高速度 |
在Intel IA32架构下,此调用约定将函数最左边两个大小小于4 个字节(DWORD的大小)的参数放在ECX和EDX寄存器。 其余规定同Pascal调用约定 |
thiscall(并非关键字) | 被调用者 | 参数入栈,this指针存ECX |
this调用约定 C++中的非静态类成员函数 |
Intel IA32架构下,此调用约定跟Pascal语言调用约定相同, 只是另外通过ECX寄存器传送一个额外的参数―this指针 |
__declspec(naked) |
裸调用约定 不能用于函数声明,只能用于函数定义 |
它只能让编译器不要生成函数体中的堆栈管理代码,但是调用函数者 依然需要前面的某种调用约定来生成调用函数的代码 |
||
register |
Delphi 调用约定 只要有可能,传递到CPU寄存器的参数能多达三个, 使函数调用操作更快 |
这种快速调用协定与Windows不兼容, Win32 API 函数必须声明使用stdcall 调用协定。 这种协定是Win16 API使用的原始Pascal 调用协定 和C语言使用的cdecl 调用协定的混合体。 |
||
_pascal | Pascal语言调用约定 | 废弃关键词 |
在C++中,可以在函数声明或定义时用关键字__stdcall指定调用约定。__stdcall调用约定经常在Windows程序或API函数中使用。在GUI程序中,PASCAL、WINAPI和CALLBACK都被定义为__stdcall。C语言的缺省调用约定为__cdecl。
__stdcall产生的名字修饰是将名字符号前加下划线(_),并且后加”@”和函数参数字节数(所需栈空间)。