孤独的猫

  博客园 :: 首页 :: 新随笔 :: 联系 :: 订阅 :: 管理 ::

函数调用详解(_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" }  

posted on 2012-11-07 22:13  孤独的猫  阅读(311)  评论(0)    收藏  举报