C++主流调用约定有__cdecl、__stdcall、__fastcall、__thiscall和__vectorcall;其中__cdecl由调用方清栈且支持可变参数,__stdcall由被调用方清栈且用于Win32 API,二者因栈清理责任和名字修饰不同导致ABI不兼容。
在 C++ 中,函数调用约定(Calling Convention)决定了函数调用时参数如何传递、栈由谁清理、函数名如何修饰等底层行为。这些约定直接影响二进制兼容性、跨语言调用(如 C++ 调用 Windows API 或 DLL)、以及汇编层的执行逻辑。
主流调用约定包括:__cdecl、__stdcall、__fastcall、__thiscall(MSVC 特有)、__vectorcall(VS2013+,用于向量化参数)。其中 __cdecl 和 __stdcall 是最基础、最常被对比的两种,尤其在 Win32 平台和 ABI 兼容场景中至关重要。
这是 Microsoft Visual C++ 的默认调用约定(对普通 C/C++ 函数),也对应大多数 Unix-like 平台的 System V ABI(尽管命名不同,逻辑相似)。
这是 Win32 API 函数(如 MessageBoxA、CreateFileW)使用的约定,也是 COM 接口的标准之一。
et 8 表示清理 8 字节参数),栈平衡由函数自身保证本质是 ABI(Application Binary Interface)层面的契约断裂:
__fastcall:前两个 DWORD(或寄存器宽度)参数通过 ECX、EDX 传递,其余压栈,callee 清栈;名字修饰为 @funcname@N。目标是减少访存,提升小函数性能。
__thiscall(MSVC 成员函数默认):this 指针放 ECX,其余参数从右到左压栈,callee 清栈(除可变参成员函数,此时 caller 清栈);名字修饰类似 __cdecl 或 __stdcall,取决于是否含可变参。
System V AMD64 ABI(Linux/macOS/x64 Windows):已统一为寄存器传参(RDI, RSI, RDX, RCX, R8, R9, R10, R11),浮点用 XMM0–XMM7,栈仅作备用和对齐;caller 清栈(但无需显式 add rsp),无名字修饰差异(C++ 仍需 mangling,但与调用约定无关)。