C++ 中 extern "C" 的调用约定是什么?

Cry*_*Man 6 c c++ windows

标题确实准确描述了我的要求。

extern "C" int foo( int bar ) { return bar; }
Run Code Online (Sandbox Code Playgroud)

从我一直在测试的内容来看,它似乎不是__cdecl, __stdcall, __fastcall,而且显然不是__thiscall

什么是约定以及它如何运作?

谢谢。

Ext*_*t3h 5

所有extern "C"决定的是名称修改。其他一切都依赖于平台。

我只能假设您正在 x86-64/win64 目标上进行测试?

如果是这样,那么所有这些调用约定都不再存在:对于 Win64,
请参阅https://docs.microsoft.com/en-us/cpp/build/x64-calling-convention?view=vs-2017
搜索“x86-64 System V ABI”以获取其他所有内容。

忽略所有指定调用约定的尝试,并使用统一的。

对于 x86,它再次依赖于平台的默认设置,因此您(过去)最好为具有多个选项的平台明确指定调用约定。


sel*_*bie 5

让我们看一下使用 32 位 Visual Studio 项目的 Debug 版本生成的程序集(默认设置):

这是我的程序:

extern "C" int func1(int x);
extern "C" int __stdcall func2(int x);
extern "C" int __cdecl func3(int x);

int main()
{
    int x = 0;
    func1(1);
    func2(2);
    func3(2);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

其中func1func2func3在单独的源文件中定义以限制自动内联的可能性。

让我们看看生成的 main 汇编代码:

    func1(1);
002117E8  push        1  
002117EA  call        _func1 (0211159h)  
002117EF  add         esp,4  
    func2(2);
002117F2  push        2  
002117F4  call        _func2@4 (0211131h)  
    func3(3);
002117F9  push        3  
002117FB  call        _func3 (021107Dh)  
00211800  add         esp,4  
Run Code Online (Sandbox Code Playgroud)

对于 func1 和 func3,它是相同的签名。参数被压入堆栈,调用函数调用,然后堆栈寄存器 (esp) 被调整回(弹出)到它的前一个地址 - 正如_cdecl调用约定所预期的那样。在 __cdecl 调用约定中,调用者负责在进行函数调用后将堆栈指针恢复到其原始地址。

调用后func2,没有堆栈指针调整。与声明的 __stdcall 调用约定一致。在 __stdcall 调用中,编译函数负责弹出堆栈指针。检查func1vs的程序集func2显示 func1 以:

00211881  ret    // return, no stack adjustment
Run Code Online (Sandbox Code Playgroud)

而 func2 以这个程序集结束:

002118E1  ret         4   // return and pop 4 bytes from stack
Run Code Online (Sandbox Code Playgroud)

现在,在您得出“无链接属性”意味着“__cdecl”的结论之前,请记住 Visual Studio 项目具有以下设置:

在此处输入图片说明

让我们将调用约定设置更改为 __stdcall 并查看生成的程序集是什么样的:

    func1(1);
003417E8  push        1  
003417EA  call        _func1@4 (034120Dh)  
    func2(2);
003417EF  push        2  
003417F1  call        _func2@4 (0341131h)  
    func3(3);
003417F6  push        3  
003417F8  call        _func3 (034107Dh)  
003417FD  add         esp,4  
Run Code Online (Sandbox Code Playgroud)

突然 main 在调用 func1 后没有弹出参数 -因此func1假定项目设置的默认调用约定。从技术上讲,这就是您的答案。

在某些环境中__stdcall,默认是常态。例如驱动程序开发...


归档时间:

查看次数:

2553 次

最近记录:

6 年,9 月 前