一、调用约定
调用约定规定了参数如何传递给函数以及调用者如何接收返回值。此外,该约定规定这些值是否通过 CPU 寄存器(和/或)堆栈传递,以及哪些寄存器可以保证在函数调用中保留它们的值。
函数调用约定是指在不同的编译器中,函数调用时,都会有一套怎样给被调函数传递参数以及怎样从被调函数中返回结果值的约定。这套约定的背后,遵循的原则是:将参数和返回值要么放在栈上,要么放在寄存器和栈的组合上。现代处理器体系结构基本上都是采用寄存器和栈的组合,即给定数目的寄存器用于存放参数和返回值,当寄存器的数目不够用时,再将多出来的参数或返回值放在栈上面。
二、C/C++ 调用约定
1、Windows 上的调用约定
调用约定
|
编译器选项
|
描述
|
---|---|---|
__cdecl
|
/Gd |
这是 C/C++ 程序的默认调用约定。
它可以在具有可变参数的函数上指定。
|
__stdcall
|
/Gz
|
用于 Win32 API 函数的标准调用约定。
|
__fastcall
|
/Gr |
指定参数在寄存器中而不是堆栈中传递的快速调用约定。
|
__regcall
|
/Qregcall
指定
__regcall
是编译中函数的默认调用约定,除非在声明中指定了另一个调用约定。
|
英特尔® C++ 编译器调用约定, 指定尽可能多的参数在寄存器中传递;同样地,
__regcall尽可能使用寄存器返回值。
|
__thiscall
|
|
不使用可变参数的 C++ 成员函数使用的默认调用约定。
|
__vectorcall
|
/Gv
|
指定传递向量类型参数的函数应使用向量寄存器的调用约定。
|
2、Linux和苹果系统的调用约定
调用约定
|
编译器选项
|
描述
|
---|---|---|
__attribute((cdecl))
|
C/C++ 程序的默认调用约定。
可以在具有可变参数的函数上指定。
|
|
__attribute((stdcall))
|
指定参数的调用约定在堆栈上传递。
不能在具有可变参数的函数上指定。
|
|
__attribute((regparm (number)))
|
在基于 IA-32 架构的系统上,regparm 属性会导致 编译器向上传递
数字寄存器中的参数 EAX, EDX,和 ECX
而不是在堆栈上。
采用可变数量参数的函数将继续在堆栈上传递
它们的所有参数。
|
|
__attribute__((regcall))
|
-regcall
指定
__regcall
是编译中函数的默认调用约定,除非在声明中指定了另一个调用约定。
|
英特尔® C++ 编译器调用约定,指定尽可能多的
参数在寄存器中传递;同样地, __regcall尽可能使用
寄存器返回值。
如果在具有可变参数的函数上指定,则忽略此调用
约定。
|
__attribute__((vectorcall))
|
|
指定传递向量类型参数的函数应使用向量寄存器的调用约定。
|
三、更多调用约定一览
在这些调用约定中,我们最常用是以下几种约定
1. cdecl
2. stdcall
3. thiscall
cdecl 是c默认的调用约定。
stdcall 他是微软Win32 API的一准标准,我们常用的回调函数就是通过这种调用方式
thiscall 是c++中非静态类成员函数的默认调用约定