函数的调用约定包括了函数的参数如何被压入栈中、函数调用后由谁来恢复堆栈等问题1
常见的调用约定2
调用约定名称 | 常见场景 | 参数入栈方式 | 栈内数据清除方式 | 备注 |
---|---|---|---|---|
__stdcall | Windows API 默认的函数调用协议 | 函数参数由右向左入栈 | 函数调用结束后由被调用函数清除栈内数据 | - |
__cdecl | C/C++ 默认的函数调用协议 | 函数参数由右向左入栈 | 函数调用结束后由函数调用者清除栈内数据 | - |
__fastcall | 适用于对性能要求较高的场合 | 从左开始不大于 4 字节的参数放入 CPU 的 ECX 和 EDX 寄存器,其余参数从右向左入栈 | 函数调用结束后由被调用函数清除栈内数据 | - |
__thiscall | C++ 类成员函数缺省的调用约定 | 函数参数由右向左入栈 | 见下文 | 这个不是编译器关键字,在 C++ 编译中不能被程序员指定 |
naked call | 很少见,一般用于实模式驱动程序设计3 | - | - | - |
__pascal4 | Pascal 的函数调用方式,也可以在 C/C++ 中使用 | 函数参数由左向右入栈 | 函数调用结束后由被调用函数清除栈内数据 | - |
__thiscall
看了不少博客,但还是看巨硬的文档比较详细: https://learn.microsoft.com/zh-cn/cpp/cpp/thiscall?view=msvc-170
mangle
不同的规范有不同的 mangle 规定,这也是 C 和 C++ 函数之间不能直接调用的原因
所以一般会有下面这种语法:
extern "C" {
// ...
}
这样里面的函数声明才能被 C 所使用,或使用 C 定义的函数