__stdcall__cdecl

Posted zhanghuan_wangkai

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了__stdcall__cdecl相关的知识,希望对你有一定的参考价值。

__cdecl 是C Declaration的缩写(declaration,声明),表示C语言默认的函数调用方法:所有参数从右到左依次入栈,这些参数由调用者清除,称为手动清栈被调用函数不会要求调用者传递多少参数,调用者传递过多或者过少的参数,甚至完全不同的参数都不会产生编译阶段的错误。

_stdcall 是StandardCall的缩写,是C++的标准调用方式:所有参数从右到左依次入栈,如果是调用类成员的话,最后一个入栈的是this指针。这些堆栈中的参数由被调用的函数在返回后清除,使用的指令是 retnX,X表示参数占用的字节数,CPU在ret之后自动弹出X个字节的堆栈空间。称为自动清栈。函数在编译的时候就必须确定参数个数,并且调用者必须严格的控制参数的生成,不能多,不能少,否则返回后会出错。

PASCAL Pascal语言函数调用方式,也可以在C/C++中使用,参数压栈顺序与前两者相反。返回时的清栈方式与_stdcall相同。 _fastcall 编译器指定的快速调用方式。由于大多数的函数参数个数很少,使用堆栈传递比较费时。因此_fastcall通常规定将前两个(或若干个)参数由寄存器传递,其余参数还是通过堆栈传递。不同编译器编译的程序规定的寄存器不同。返回方式和_stdcall相当。 _thiscall 是为了解决类成员调用中this指针传递而规定的。_thiscall要求把this指针放在特定寄存器中,该寄存器由编译器决定。VC使用ecx,Borland的C++编译器使用eax。返回方式和_stdcall相当。 _fastcall 和 _thiscall涉及的寄存器由 编译器决定,因此不能用作跨编译器的接口。所以Windows上的COM对象接口都定义为_stdcall调用方式。 C中不加说明默认函数为_cdecl方式(C中也只能用这种方式),C++也一样,但是默认的调用方式可以在IDE环境中设置。 __cdecl __fastcall与 __stdcall,三者都是调用约定(Calling convention),它决定以下内容:1)函数参数的压栈顺序,2)由调用者还是被调用者把参数弹出栈,3)以及产生函数修饰名的方法。 1、__stdcall调用约定:函数的参数自右向左通过栈传递,被调用的函数在返回前清理传送参数的内存栈。 2、__cdecl是C和C++程序的缺省调用方式。每一个调用它的函数都包含清空 堆栈的代码,所以产生的 可执行文件大小会比调用_stdcall函数的大。函数采用从右到左的压栈方式。注意:对于可变参数的成员函数,始终使用__cdecl的转换方式。 3、__fastcall调用约定:它是通过 寄存器来传送参数的(实际上,它用ECX和EDX传送前两个双字(DWORD)或更小的参数,剩下的参数仍旧自右向左压栈传送,被调用的函数在返回前清理传送参数的内存栈)。 4、thiscall仅仅应用于"C++"成员函数。this 指针存放于CX寄存器,参数从右到左压。thiscall不是关键词,因此不能被程序员指定。

在windef.h头文件中有如下定义

#define WINAPI      __stdcall
#define APIENTRY    WINAPI

VC有两种函数调用方式 一种是__stdcall,另一种是__cdecl
函数的调用方式有两种一种是PASCAL调用方式,另一种是C调用方式
使用PASCAL调用方式,函数在返回到调用者之前将参数从栈中删除
使用C调用方式,参数的删除是调用者完成的
WinMain函数是由系统调用的,Windows系统规定由系统调用的函数都遵守PASCAL调用方式
但是VC中函数的缺省调用方式是__cdecl,也就是C调用方式
所以在WinMain前显示的声明。
在Windows编程中将遇到很多声明修饰符,如CALLBACK,WINAPI,PASCAL这些在IntelCPU的计算机上都是__stdcall

详细的声明细节请看windef.h文件  


我们知道,我们的API函数都是从动态链接库中引入的,最重要的两个动态链接库是:
user32.dll 和 Kernel32.dll, 所以这里的的函数必然也是从动态链接库中链入的;

然后就是对__stdcall的一个粗略的介绍,目的是对这个关键词不要恐惧;其实,函数的调用方式是有很多种的,具体体现在:参数的调用方式和返回值的方式,可以是通过压栈,也可以通过寄存器传递等;这样的话,就有必要对各种调用方式进行规范;我们这里提到的__stdcall调用规范主要是:
1)Argument-passing order:          Right to left.
2)Argument-passing convention:     By value, unless a pointer or reference type is passed.
3)Stack-maintenance responsibility:Called function pops its own arguments from the stack.
4)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
5)Case-translation convention:     None

最后:The __stdcall calling convention is used to call Win32 API functions,所以,我们在调用Win32 API时,这个关键字总是出现的!
其他相关的关键字为: 
__cdecl用于C/C++;  
__clrcall用于修饰托管代码;
__fastcall用于修饰用寄存器传递参数的函数,调用速度很快,所以就fast!
__thiscall用于修饰C++成员函数的调用;



以上是关于__stdcall__cdecl的主要内容,如果未能解决你的问题,请参考以下文章

函数调用方法之__cdecl与_stdcall

stdcall与cdecl的区别

__stdcall __cdecl的区别

转:函数调用的区别:_cdecl以及_stdcall

_STDCALL&_CDECL 调用约定

_stdcall 与 _cdecl 区别