【C/C++】调用约定

245 阅读2分钟

「这是我参与2022首次更文挑战的第4天,活动详情查看:2022首次更文挑战」。

C/C++ 中的函数原型为:[连接规范]函数类型 [调用约定]函数名 参数列表 {......}

那么,其中的 调用约定 是什么呢?

函数堆栈

当一个函数被调用时,进程内核对象为其在进程的地址空间的堆栈部分分配一定的栈内存给该函数使用,函数堆栈功能如下:

  1. 进入函数前,保存“返回地址”和环境变量。返回地址是指该函数结束后,从进入该函数之前的那个地址继续执行下去。
  2. 进入函数后,保存实参或实参复制、局部变量。

调用约定

调用约定是决定函数实参或实参复制进入和退出函数堆栈的方式以及函数堆栈释放的方式,也就是实参或实参复制入栈、出栈、函数堆栈释放的方式。

调用约定的类型

在Win32下有以下4种:

  1. _cdecl :默认调用方式
    • 实参是以参数列表从右依次向左入栈,出栈相反,函数堆栈由调用方来释放
    • 主要用在那些带有可变参数的函数上,对于传送参数的内存栈是由调用者来维护的
    • 由于每一个调用它的函数都包含清空堆栈的代码,所以产生的可执行文件大小会比调用 _stdcall 函数的大。
  2. _stdcall:WIN API的调用约定
    • 实参以参数列表从右依次向左入栈,出栈相反。函数堆栈是由被调用方自己释放的
    • COM接口等只要是声明定义接口都要显式指定其调用约定为_stdcall
    • 若函数含有可变参数,那么即使显式指定了_stdcal,编译器也会自动把其改变成 _cdecl
  3. _thiscall:类的非静态成员函数默认的调用约定
    • 实参以参数列表从右依次向左入栈,出栈相反。函数堆栈是由被调用方自己释放的
    • 其不能用在含有可变参数的函数上,否则编译会出错
    • 类的非静态成员函数内部都隐含有一个this指针,该指针不是存放在函数堆栈上的,而是直接存放在CPU寄存器上的。
  4. _fastcall: 快速调用
    • 实参并不是存放在函数堆栈上,而是直接存放在CPU寄存器上,所以不存在入栈、出栈、函数堆栈释放。