函数调用详解(_cdecl,_stdcall,_pascal)
函数调用详解(_cdecl,_stdcall,_pascal)
摘自:http://hi.baidu.com/gcwuzaawqpkorsr/item/416481199653589d98ce3378
函数调用有几种方式,第一种是C方式,在C和C++中这种函数调用方式是缺省的;第二种是pascal方式,类的成员函数缺省调用是_stdcall。在32位的 VC++5.0及以上中PASCAL 调用约定不再被支持(实际上它已被定义为_stdcall。除了_pascal外,_fortran 和_syscall也不被支持),取而代之的是_stdcall调用约定。
一:差别
1. _cdecl(c和c++缺省的函数调用方式)
这种调用方式按从右到左的顺序压参数入栈,由调用者把参数弹出栈,对栈的管理也是由调用者,它的优点是支持printf这样的可变参数调用。一般可变参数函数的调用都采用这种方式,比如int __cdecl scanf (const char *format,…)。
这种函数调用的修饰方式是这样的:例如:function(int a, int b),调用约定仅在输出函数名前加上一个下划线前缀,格式为_function。
2. WINAPI (实际上就是PASCAL,CALLBACK,_stdcall)
_stdcall 是 Pascal 程序的缺省调用方式,通常用于 Win32 API 中,函数采用从右到左的压栈方式,自己在退出时清空堆栈。这种调用方式不能实现变参函数,因为被调函数不能事先知道弹栈数量,但在主调函数中是可以做到的,因为参数数量由主调函数确定。
_stdcall调用约定在输出函数名前加上一个下划线前缀,后面加上一个"@"符号和其参数的字节数,格式为,例如 :function(int a, int b),其修饰名为:。
二:举例
有如下例子:
void func(int a, int b, int c, int d)
{ ………… }
使用函数如下
int main()
{
func(1, 2, 3, 4);
}
1. 如果函数是以_cdecl调用,情况就是如下:
int main()
{ //参数从右到左压栈
push 4
push 3
push 2
push 1
call func add esp 0x10
//调用者恢复堆栈指针esp,4个参数的大小是0x10(4x4) }
2. 如果函数是以_stdcall调用,情况如下
int main()
{ //参数从右到左压栈
push 4
push 3
push 2
push 1
call func
//恢复堆栈指针由被调用者func负责,方法是"ret 0x10" }
3. 如果函数是以_pascal调用,情况如下
int main() {
//参数从左到右压栈
push 1
push 2
push 3
push 4
call func
//恢复堆栈指针由被调用者func负责,方法是"ret 0x10" }

浙公网安备 33010602011771号