标题确实准确描述了我的要求。
extern "C" int foo( int bar ) { return bar; }
Run Code Online (Sandbox Code Playgroud)
从我一直在测试的内容来看,它似乎不是__cdecl, __stdcall, __fastcall,而且显然不是__thiscall。
什么是约定以及它如何运作?
谢谢。
所有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,它再次依赖于平台的默认设置,因此您(过去)最好为具有多个选项的平台明确指定调用约定。
让我们看一下使用 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)
其中func1、func2和func3在单独的源文件中定义以限制自动内联的可能性。
让我们看看生成的 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 次 |
| 最近记录: |