调用约定_stdcall _cdecl _fastcall的区别

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调用约定在输出函数名前加上一个下划线前缀,后面加上一个“@”符号和其参数的字节数,格式为[email protected]。如函数int sub(int a, int b)的修饰名是[email protected]

1.3 _fastcall调用约定

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

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

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

  (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 [email protected] @[email protected]

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

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

时间: 2024-10-11 22:48:59

调用约定_stdcall _cdecl _fastcall的区别的相关文章

_stdcall,_cdecl区别

(1) _stdcall调用 _stdcall是Pascal程序的缺省调用方式,参数采用从右到左的压栈方式,被调函数自身在返回前清空堆栈. WIN32 Api都采用_stdcall调用方式,这样的宏定义说明了问题: #define WINAPI _stdcall 按C编译方式,_stdcall调用约定在输出函数名前面加下划线,后面加"@"符号和参数的字节数,形如 _[email protected]. ? (2) _cdecl调用 _cdecl是C/C++的缺省调用方式,参数采用从右到

3种调用约定的区别与联系

由C代码到汇编代码来看看cdecl.stdcall.fastcall三个调用约定的区别: int __stdcall add1(int x,int y) { return x + y; } int __cdecl add2(int x, int y) { return x + y; } int __fastcall add3(int x, int y,int z) { return x + y +z; } int _tmain(int argc, _TCHAR* argv[]) { add1(1

__cdecl、_stdcall、_fastcall、_thiscall

1. 介绍 __cdecl 是C Declaration的缩写(declaration,声明),表示C语言默认的函数调用方法:所有参数从右到左依次入栈,这些参数由调用者清除,称为手动清栈.被调用函数不会要求调用者传递多少参数,调用者传递过多或者过少的参数,甚至完全不同的参数都不会产生编译阶段的错误. _stdcall 是StandardCall的缩写,是C++的标准调用方式:所有参数从右到左依次入栈,如果是调用类成员的话,最后一个入栈的是this指针.这些堆栈中的参数由被调用的函数在返回后清除,

C/C++:函数的编译方式与调用约定以及extern “C”的使用

函数在C++编译方式与C编译方式下的主要不同在于:由于C++引入了函数重载(overload),因此编译器对同名函数进行了名称重整(name mangle).因此,在C++中引 用其他C函数库时,需要对声明使用的函数做适当的处理,以告知编译器做出适应的名称处理. 函数的调用约定涉及了函数参数的入栈顺序.清栈主体(负责清理栈的主体:函数自身还是调用函数者?).部分名称重整. 如,在C编译方式下有_stdcall._cdecl等调用约定,在C++编译方式下也有_stdcall._cedecl等调用约

几种调用约定

调用约定(Callingconvention)决定以下内容:函数参数的压栈顺序,由调用者还是被调用者把参数弹出栈,以及产生函数修饰名的方法.MFC支持以下调用约定: 1._cdecl 按从右至左的顺序压参数入栈,由调用者把参数弹出栈.对于"C"函数或者变量,修饰名是在函数名前加下划线.对于"C++"函数,有所不同. 如函数voidtest(void)的修饰名是_test:对于不属于一个类的"C++"全局函数,修饰名是[email protecte

DLL中调用约定和名称修饰(一)

DLL中调用约定和名称修饰(一) 调用约定(Calling Convention)是指在程序设计语言中为了实现函数调用而建立的一种协议.这种协议规定了该语言的函数中的参数传送方式.参数是否可变和由谁来处理堆栈等问题.不同的语言定义了不同的调用约定. 在C++中,为了允许操作符重载和函数重载,C++编译器往往按照某种规则改写每一个入口点的符号名,以便允许同一个名字(具有不同的参数类型或者是不同的作用域)有多个用法,而不会打破现有的基于C的链接器.这项技术通常被称为名称改编(Name Manglin

_stdcall ,_cdecl,__fastcall 深入解析

成相对独立的功能,它们彼此协作来完成整个软件系统的工作.可能存在一些模块的功能较为通用,在构造其它软件系统时仍会被使用.在构造软件系统时,如果将所有模块的源代码都静态编译到整个应用程序 EXE 文件中,会产生一些问题:一个缺点是增加了应用程序的大小,它会占用更多的磁盘空间,程序运行时也会消耗较大的内存空间,造成系统资源的浪费:另一个缺点是,在编写大的 EXE 程序时,在每次修改重建时都必须调整编译所有源代码,增加了编译过程的复杂性,也不利于阶段性的单元测试. Windows 系统平台上提供了一种

调用约定

调用约定(Calling convention)决定以下内容:函数参数的压栈顺序,由调用者还是被调用者把参数弹出栈,以及产生函数修饰名的方法. 最常用的两种 Calling convention: ① _cdecl          按从右至左的顺序压参数入栈,由调用者把参数弹出栈.对于"C"函数或者变量,修饰名是在函数名前加下划线.对于"C++"函数,有所不同.     如函数void     test(void)的修饰名是_test:对于不属于一个类的"

C++调用约定和名字约定

调用约定是指程序在函数调用时传递参数和获取返回值所采用的方法:通过寄存器.或通过栈.或者是两者的混合.用于指定Calling Convention的修饰符主要有:__cdecl,__stdcall,__fastcall等.调用约定可以通过工程设置:Setting...\C/C++ \Advanced\CallingConvention 项进行选择,缺省状态为__cdecl.它们决定以下内容: 1).函数参数的压栈顺序, 2).由调用者还是被调用者把参数弹出栈, 3).以及产生函数修饰名的方法.