函数调用约定:_stdcall、_cdecl、_fastcall

来源:互联网 发布:武汉核运行研究所 知乎 编辑:程序博客网 时间:2024/05/14 22:59

(1) _stdcall调用
  _stdcall 是Standard Call的缩写,是C++的标准调用方式,也是Pascal程序的缺省调用方式,参数采用从右到左的压栈方式,如果是调用类成员的话,最后一个入栈的是this指针。这些堆栈中的参数由被调函数自身在返回前清空,使用的指令是 retn X,X表示参数占用的字节数,CPU在ret之后自动弹出X个字节的堆栈空间。称为自动清栈。
  WIN32 Api都采用_stdcall调用方式,这样的宏定义说明了问题:
  #define WINAPI _stdcall
  按C编译方式,_stdcall调用约定在输出函数名前面加下划线,后面加“@”符号和参数的字节数,形如_functionname@number。

(2) _cdecl调用
  _cdecl是C Declaration[声明]的缩写,表示C/C++语言默认的函数调用方法,也是C/C++的缺省调用方式,所有参数从右到左依次入栈,这些参数由调用者清除,称为手动清栈。_cedcl约定的函数只能被C/C++调用,每一个调用它的函数都包含清空堆栈的代码,所以产生的可执行文件大小会比调用_stdcall函数的大。被调用函数无需要求调用者传递多少参数,调用者传递过多或者过少的参数,甚至完全不同的参数都不会产生编译阶段的错误。

  由于_cdecl调用方式的参数内存栈由调用者维护,所以变长参数的函数能(也只能)使用这种调用约定。

  由于Visual C++默认采用_cdecl 调用方式,所以VC中中调用DLL时,用户应使用_stdcall调用约定。
  按C编译方式,_cdecl调用约定仅在输出函数名前面加下划线,形如_functionname。

(3) _fastcall调用
  _fastcall 是编译器指定的快速调用方式。由于大多数的函数参数个数很少,使用堆栈传递比较费时。因此_fastcall通常规定将前两个(或若干个)参数由寄存器传递,其余参数还是通过堆栈传递。不同编译器编译的程序规定的寄存器不同。返回方式和_stdcall相当。
  _fastcall调用较快,它通过CPU内部寄存器传递参数。

 

(4)PASCAL调用

PASCAL 是Pascal语言的函数调用方式,也可以在C/C++中使用,参数压栈顺序与_cdecl和_stdcall相反。

 

归纳如下:
调用约定            入栈参数清理         参数入栈顺序
-----------        --------------         ----------------
cdecl           调用者处理         右->左
stdcall         函数自己处理       右->左
fastcall        函数自己处理     依赖于编译器

pascal          函数自己处理       左->右