函数调用约定(Calling convention)是在函数调用时关于函数参数入栈和出栈的顺序的约定,即由调用者还是被调用者把参数弹出栈。
几乎每一种语言都有函数的概念,而作为函数就有参数。一般来说,参数的传递是通过堆栈完成的(堆栈是一种先进后出的数据结构),总的传递过程是这样:函数调用时,由调用者依次把参数压栈,然后调用函数,函数被调用以后,在堆栈中取得数据并进行计算。函数计算结束以后,或者调用者、或者函数本身修改堆栈,使堆栈恢复原状。至于多个参数按照什么顺序把参数压入堆栈;以及函数调用后,由谁来把堆栈恢复原状;则是不同的函数调用约定要解决的两个问题。
在C++中,主要有五种调用约定。我们还是以前面的Entry和Function函数为例来说明它们。两个函数中,Entry是调用者,而Function是被调用者,假若Function函数的原型是这样:int Function ( int a, int b );不同的调用约定是在Function函数前加上不同的修饰符或者让Function成为类的成员而实现的。
(1)_cdecl调用约定。
_cdecl调用约定又称为C调用约定,是C语言缺省的调用约定,也是C++对于全局函数(不属于类的函数)的缺省调用约定。它的定义语法是:
当Entry调用Function时,参数由Entry负责从右向左压入堆栈,Function使用参数得到的是从左向右的正序序列,Function函数本身不负责清理堆栈,而由Entry负责清理堆栈。正是由于这种约定,C调用约定允许函数的参数的个数是可变的,这也是C语言的一大特色。
(2)_ stdcall调用约定。
_stdcall很多时候被称为pascal调用约定,因为pascal是早期很常见的一种教学用计算机程序设计语言,其语法严谨,使用的函数调用约定就是stdcall。在Microsoft C++系列的C/C++编译器中,常常用PASCAL宏来声明这个调用约定,类似的宏还有WINAPI和CALLBACK。_stdcall调用约定声明的语法为:
_stdcall的调用约定意味着:当Entry调用Function时,参数由Entry负责从右向左压入堆栈,Function使用参数得到的是从左向右的正序序列,Function函数本身负责清理堆栈。(www.xing528.com)
(3)thiscall调用约定。
仅仅用于C++成员函数。this指针存放于ECX寄存器,参数从右向左压栈,thiscall不是关键字,因此不能用于修饰函数。
(4)_fastcall调用约定。
_fastcall调用约定和stdcall类似,它意味着:函数的第一个和第二个DWORD参数(或者尺寸更小的)通过ECX和EDX寄存器传递,其它参数通过从右向左的顺序压栈,被调用函数清理堆栈。其声明语法为:
int _fastcall Function(int a, int b);
(5)naked call调用约定。
这是一个很少见的调用约定,一般程序设计者建议不要使用。编译器不会给这种函数增加初始化和清理代码。naked call不能独自作为修饰符,必须和_declspec共同使用,如下所示:
上面的五种调用约定,前三种比较常用。DLL所使用的调用约定一般要求是_cdecl调用约定,主要为了使DLL能更好的重用,还有就是因为函数名字修饰的约定。
免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。