码迷,mamicode.com
首页 > 其他好文 > 详细

调用约定_stdcall _cdecl _fastcall的区别

时间:2017-09-01 13:40:33      阅读:288      评论:0      收藏:0      [点我收藏+]

标签:function   调试   center   art   描述   1.2   .net   prim   order   

1.函数调用约定

函数的调用约定,顾名思义就是对函数调用的一个约束和规定(规范),描述了函数参数是怎么传递和由谁清除堆栈的。它决定以下内容:

  (1) 函数参数的压栈顺序;

  (2) 由调用者还是被调用者把参数弹出栈;

  (3) 产生函数修饰名的方法;

 

在看C++ primer中就提到函数声明包括:返回值类型,函数名,形参列表

int function();
int add(int a,int b);

 上面的函数声明方式是我们经常用到的,其实还有一部分就是调用约定,目前存在:_cdecl、_stdcall、_fastcall、_pascall、_thiscall、_vectorvcall。我们使用的较为广泛的调用是_cedcl、_stdcall以及_fastcall。下面分别讲述一下各个调用约定的含义。

 

1.1 _cdecl调用约定

  __cdecl 是 C Declaration 的缩写,是C/C++和MFC的默认调用约定。其具有如下的特点:

  (1) 按从右至左的顺序压参数入栈;

  (2)由调用者把参数弹出栈;切记:对于传送参数的内存栈是由调用者来维护的,返回值在EAX中。因此对于像printf这样可变参数的函数必须用这种约定。

  (3)编译器在编译的时候对这种调用规则的函数生成修饰名的时候,在输出函数名前加上一个下划线前缀,格式为_function。如函数int add(int a, int b)的修饰名是_add。

 

1.2 _stdcall调用约定

  __stdcall是Standard Call的缩写,是C++的标准调用方式,是微软定义的标准,__stdcall通常用于Win32 API中(可查看WINAPI的定义)。

  (1)按从右至左的顺序压参数入栈

  (2)由被调用者把参数弹出栈。切记:函数自己在退出时清空堆栈,返回值在EAX中。

  (3)__stdcall调用约定在输出函数名前加上一个下划线前缀,后面加上一个“@”符号和其参数的字节数,格式为_function@number。如函数int sub(int a, int b)的修饰名是_sub@8

 

1.3 _fastcall调用约定

  __fastcall调用的主要特点就是快,因为它是通过寄存器来传送参数的。

  (1)实际上__fastcall用ECX和EDX传送前两个DWORD或更小的参数,剩下的参数仍自右向左压栈传送,被调用的函数在返回前清理传送参数的内存栈。

  (2)__fastcall调用约定在输出函数名前加上一个“@”符号,后面也是一个“@”符号和其参数的字节数,格式为@function@number,如double multi(double a, double b)的修饰名是@multi@16。

  (3)__fastcall和__stdcall很象,唯一差别就是头两个参数通过寄存器传送。注意通过寄存器传送的两个参数是从左向右的,即第1个参数进ECX,第2个进EDX,其他参数是从右向左的入栈,返回仍然通过EAX。

 

1.4 _thiscall调用约定

  __thiscall是C++类成员函数缺省的调用约定,但它没有显示的声明形式。因为在C++类中,成员函数调用还有一个this指针参数,因此必须特殊处理,thiscall调用约定的特点:

  (1)参数入栈:参数从右向左入栈

  (2)this指针入栈:如果参数个数确定,this指针通过ecx传递给被调用者;如果参数个数不确定,this指针在所有参数压栈后被压入栈。

  (3)栈恢复:对参数个数不定的,调用者清理栈,否则函数自己清理栈。

 

2.总结

特点 _cdecl _stdcall _fastcall
参数传递方式 从右向左 从右向左 左边开始的两个不大于4字节(DWORD)的参数分别放在ECX和EDX寄存器,其余的参数自右向左压栈传送
清理栈方式  调用者清理 被调用函数清理 被调用函数清理
使用场合 C/C++、MFC的默认方式; 可变参数的时候使用; Win API 要求速度快
编译修饰约定 _functionname _functionname@number @functionname@number

 

  从代码和程序调试的层面考虑,参数的压栈顺序和栈的清理我们都不用太观注,因为这是编译器的决定的,我们改变不了。但第三点却常常困扰我们,因为如果不弄清楚这点,在多个库之间(如dll、lib、exe)相互调用、依赖时常常出出现莫名其妙的错误

 

以上内容参考:http://blog.csdn.net/luoweifu/article/details/52425733

 

调用约定_stdcall _cdecl _fastcall的区别

标签:function   调试   center   art   描述   1.2   .net   prim   order   

原文地址:http://www.cnblogs.com/chmm/p/7461563.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!