摘要:本文简要综述了几种常见的函数调用方式。
关键字:__stdcall,__cdecl,__thisclass,_fastcall
我们经常可以看到这样的函数声明:
void __cdecl fun();
void __stdcall fun();
其中修饰符__cdecl和__stdcall决定了函数的调用方式,具体涉及到三个方面:
1)函数参数的压栈顺序,
2)由函数调用者还是被调用者将参数出栈,
3)决定函数的修饰符和命名方式。
常见的调用方式有__cdecl,__stdcall,__fastcall,__thisclall
,具体介绍如下:
__cdcel
__cdcel它是CDeclaration的缩写,为C语言默认的函数调用方式,这种调用方式下,所有参数从右到左
依次入栈,这些参数由调用者清除,称为手动清栈所有参数从右到左依次入栈,这些参数由调用者清除,称
为手动清栈。被调用函数不需要求调用者传递多少参数,调用者传递过多或者过少的参数,甚至完全不同的
参数都不会产生编译阶段的错误。调用约定仅在输出函数名前加上一个下划线前缀,格式_functionname。
__stdcall
__stdcall是C++的标准调用方式(也是Pascal程序的缺省调用方式),所有参数从右到左依次入栈,如果
是调用类成员的话,最后一个入栈的是this指针。这些堆栈中的参数由被调用的函数在返回后清除,使用的
指令是 retnX,X表示参数占用的字节数,CPU在ret之后自动弹出X个字节的堆栈空间。称为自动清栈。
__stdcall
__stdcall调用约定在输出函数名前加上一个下划线前缀,后面加上一个”@”符号和其参数的字节数,格式
,例如 :function(int a, int b),其修饰名为:。另外,函数在编译的
时候就必须确定参数个数,并且调用者必须严格的控制参数的生成。
__fastcall
__fastcall是编译器指定的快速调用方式。由于大多数的函数参数个数很少,使用堆栈传递比较费时。
因此_fastcall通常规定将前两个(或若干个)参数由寄存器传递,其余参数还是通过堆栈传递。不同编译器
编译的程序规定的寄存器不同。返回方式和_stdcall相同。调用约定在输出函数名前加上一个”@”符号,后
面也是一个”@”符号和其参数的字节数,格式为@functionname@number。
__thiscall
__thiscall是为了解决类成员调用中this指针传递而规定的,仅仅应用于”C++”成员函数,另外,thiscall
不是关键词,因此不能被程序员指定。_thiscall要求把this指针放在特定寄存器中,该寄存器由编译器决
定。VC使用ecx,Borland的C++编译器使用eax。返回的方式和_stdcall相同。_fastcall和 _thiscall涉及的
寄存器由编译器决定,因此不能用作跨编译器的接口。所以Windows上的COM对象接口都定义为_stdcall调用方式。