函数调用方式解析

  Calling Convertion,不同的函数调用方式往往会导致混合编程中相互调用的出错。C++默认使用的是的__cdecl方式,这样生成的DLL如果在 DELPHI中使用stdcall方式调用是会出错的,下文对各种主要的函数调用方式做了一个比较详细的解释。


函数调用的不同方式

Visual C/C++编译器使用若干种方式来调用内部和外部的函数。理解这些不同的方式有助于我们来调试程序和链接我们的代码。以下文字解释了不同的函数调用方式下,参数的传递,函数返回值的返回等。同时,也讨论了无参函数的调用。

Visual C/C++ 支持若干种不同的函数调用转换。所有的参数再传递时被设置为32位大小。除了8byte的结构体返回在EDX:EAX寄存器对上,其他的返回值也被设置为 32位,并且返回在EAX寄存器中。大的结构体则以一个指向隐藏的返回结构体指针保存在EAX寄存器中。参数是从右向左压入堆栈中。如果寄存器ESI, EDI,EBX,EBP寄存器在函数中使用,编译器产生prolog和epilog代码来保存和恢复它们。

Visual C/C++ 编译器支持以下的调用转换:
关键字               堆栈清除者    参数传递
__cdecl              调用者       从右向左的顺序压入堆栈内
__stdcall            被调用者     从右向左的顺序压入堆栈内
__fastcall           被调用者     保存在寄存器中,然后其他的压入堆栈内
thiscall(非关键字)    被调用者     压入堆栈,this指针保存在ECX寄存器内

调用方式解析:
void    calltype MyFunc( char c, short s, int i, double f );
calltype代表不同的调用方式

__cdecl调用:
在VC中的编译器选项是/Gd。这是C和C++程序的缺省函数调用转换方式。由于堆栈是由调用者清除的,所以它能调用vararg函数。以__cdecl 调用方式编译的程序比__stdcall大,因为以__stdcall方式编译的程序需要在每个函数调用中包含堆栈清空的代码。
以C方式修饰的函数名是_MyFunc。
__cdecl调用方式的示例图:


__stdcall调用:
在VC中的编译器选项是/Gz。
以C方式修饰的函数名是_MyFunc@20。20是参数的字节数(5×4bytes)。C++方式修饰的名称是私有的,各个编译器可能不同。
 __stdcall and thiscall 调用方式的示例图:

 __fastcall调用:
 在VC中的编译器选项是/Gr。
以C方式修饰的函数名是@MyFunc@20。C++方式修饰的名称是私有的,各个编译器可能不同。
__fastcall调用方式的示例图:

thiscall调用:
这是无参C++成员函数的默认调用方式。调用者负责清空堆栈,this指针第一个入栈。因为没有对应的关键字,所以thiscall方式的调用不可在程序中被显式定义。所有的函数参数都压入堆栈。这种调用方式只应用于C++,所以没有C方式的命名修饰。

你可能感兴趣的:(职场,休闲,函数调用,__stdcall)