_stdcall 与 _cdecl
几乎我们写的每一个WINDOWS API函数都是__stdcall类型的,首先,需要了解两者之间的区别: WINDOWS的函数调用时需要用到栈(STACK,一种先入后出的存储结构)。当函数调用完成后,栈需要清除,这里就是问题的关键,如何清除??
如果我们的函数使用了_cdecl,那么栈的清除工作是由调用者,用COM的术语来讲就是客户来完成的。这样带来了一个棘手的问题,不同的编译器产生栈的方式不尽相同,那么调用者能否正常的完成清除工作呢?答案是不能。
如果使用__stdcall,上面的问题就解决了,函数自己解决清除工作。所以,在跨(开发)平台的调用中,我们都使用__stdcall(虽然有时是以WINAPI的样子出现)。
那么为什么还需要_cdecl呢?当我们遇到这样的函数如fprintf()它的参数是可变的,不定长的,被调用者事先无法知道参数的长度,事后的清除工作也无法正常的进行,因此,这种情况我们只能使用_cdecl。到这里我们有一个结论,如果你的程序中没有涉及可变参数,最好使用__stdcall关键字。
函数声明后面加个stdcall是什么意思push Var3
push Var2
push Var1
call SubRouting
add esp,12
也就是说,调用者首先把参数压入堆栈,然后调用子程序,在完成后,由于堆栈中先前压入的数不再有用,调用者或者被调用者必须有一方把堆栈指针修正到调用前的状态。参数是最右边的先入堆栈还是最左边的先入堆栈、还有由调用者还是被调用者来修正堆栈都必须有个约定,不然就会产生不正确的结果,而Stdcall就是参数从右到左压入栈,由被调用的子程序来修正堆栈的指针。
register Left-to-right Routine Yes
pascal Left-to-right Routine No
cdecl Right-to-left Caller No
stdcall Right-to-left Routine No
safecall Right-to-left Routine No
msdn
_stdcall是一种函数调用习惯!说明函数的参数是从右往左进栈的!
用法:放在函数声明前
而且好像是调用者自己清stack的
看msdn中有关vc的函数调用修饰词解说的
int func(int x)
int func(int x,...)
不知道我有没有记错。
前一个各种调用方式都可以。
而后一个只能用c调用方式,因为被调用函数并不知道调用者向stack里面压了多少参数。
调用约定
调用约定(calling convention)决定以下内容:函数参数的压栈顺序,由调用者还是被
调用者把参数弹出栈,以及产生函数修饰名的方法。mfc支持以下调用约定:
1、_cdecl
按从右至左的顺序压参数入栈,由调用者把参数弹出栈。对于“c”函数或者变量,修饰
名是在函数名前加下划线。对于“c++”函数,有所不同。
如函数void test(void)的修饰名是_test;对于不属于一个类的“c++”全局函数,修饰
名是?test@@zaxxz。
这是mfc缺省调用约定。由于是调用者负责把参数弹出栈,所以可以给函数定义个数不定
的参数,如printf函数。
2、_stdcall
按从右至左的顺序压参数入栈,由被调用者把参数弹出栈。对于“c”函数或者变量,修
饰名以下划线为前缀,然后是函数名,然后是符号“@”及参数的字节数,如函数int f
unc(int a, double b)的修饰名是_func@12。对于“c++”函数,则有所不同。所有的w
in32 api函数都遵循该约定。
3、_fastcall
头两个dword类型或者占更少字节的参数被放入ecx和edx寄存器,其他剩下的参数按从右
到左的顺序压入栈。由被调用者把参数弹出栈,对于“c”函数或者变量,修饰名以“@
”为前缀,然后是函数名,接着是符号“@”及参数的字节数,如函数int func(int a,
double b)的修饰名是@func@12。对于“c++”函数,有所不同。未来的编译器可能使用
不同的寄存器来存放参数。
4、thiscall
仅仅应用于“c++”成员函数。this指针存放于cx寄存器,参数从右到左压栈。thiscal
l不是关键词,因此不能被程序员指定。
5、naked call
采用1-4的调用约定时,如果必要的话,进入函数时编译器会产生代码来保存esi,edi,
ebx,ebp寄存器,退出函数时则产生代码恢复这些寄存器的内容。naked call不产生这 样的代码。
naked call不是类型修饰符,故必须和_declspec共同使用,如下:
__declspec( naked ) int func( formal_parameters )
{
// function body
}
在mfc中有以下宏定义:
#define callback __stdcall
#define winapi __stdcall
#define winapiv __cdecl
#define apientry winapi
#define apiprivate __stdcall
#define pascal __stdcall