C/C++学习笔记 关于调用约定

Posted 坐望云起

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C/C++学习笔记 关于调用约定相关的知识,希望对你有一定的参考价值。

一、调用约定

        调用约定规定了参数如何传递给函数以及调用者如何接收返回值。此外,该约定规定这些值是否通过 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++中非静态类成员函数的默认调用约定

以上是关于C/C++学习笔记 关于调用约定的主要内容,如果未能解决你的问题,请参考以下文章

C/C++函数的调用约定详解

C/C++学习笔记:你必须学会的5种C/C++函数调用的方式?

三种函数调用约定

汇编 ? cdecl 函数调用约定,stdcall 函数调用约定

C调用约定__cdecl__stdcall__fastcall__pascal分析

x86 x64下调用约定浅析