【问题标题】:Which calling convention is used for functions exported via .def file?哪个调用约定用于通过 .def 文件导出的函数?
【发布时间】:2013-07-18 11:56:57
【问题描述】:

我正在用 Visual C++ 编译一些第三方 C 代码。源代码树包含以下 .def 文件:

LIBRARY "ThirdParty.dll"

EXPORTS
   ThirdPartyFunction @1

ThirdPartyFunction() 定义附近没有明确的调用约定规范(如__stdcall__cdecl)。 Visual C++ 项目属性(C++ -> 高级 -> 调用约定)设置为 __cdecl (/Gd)

导出的函数将使用哪种调用约定,我如何确保它是该约定?

【问题讨论】:

  • This answer 可能无济于事,但如果您还没有看到它,它可能会有用。
  • @RogerRowland:实际上它确实有帮助 - 我使用了 Depends 并查看了导出的符号,我发现它们没有被装饰,所以它是 __cdecl
  • 默认情况下,__cdecl 函数也会被修饰。

标签: c visual-c++ calling-convention


【解决方案1】:

.def 文件不控制调用约定,它完全由编译器决定。如果您没有在函数声明中显式使用 __cdecl 或 __stdcall,那么它是编译器的默认值,因此 __cdecl。极端情况是 __thiscall 用于 C++ 成员函数,而 __clrcall 用于托管代码。

调用约定还选择了名称装饰样式,这是专门为避免客户端代码出错而发明的。 __cdecl 在名称前添加一个下划线,__stdcall 附加“@n”,其中 n 是堆栈激活帧的大小。当客户端代码使用参数类型或数量不匹配的错误声明时,它可以防止堆栈不平衡,这是一个致命且很难诊断 __stdcall 的问题。使用 .def 文件禁用此装饰实际上是一个坏主意,并且只有在使用 LoadLibrary+GetProcAddress 动态加载 DLL 时才应考虑。如果您打算让非 C/C++ 客户端使用您的 DLL,那么显式使用 __stdcall 通常是个好主意,因为这往往是其他语言运行时的默认设置。

这对于 64 位代码都无关紧要,它只有一个调用约定。虽然通过添加 __vectorcall 调用约定,看起来微软是 about to mess that up

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-16
    • 1970-01-01
    • 1970-01-01
    • 2012-11-29
    相关资源
    最近更新 更多