我正在用Visual C ++编译一些第三方C代码。源树包含以下.def文件:
LIBRARY "ThirdParty.dll"
EXPORTS
ThirdPartyFunction @1
并且__stdcall
定义附近没有明确的调用约定规范(如__cdecl
或ThirdPartyFunction()
)。 Visual C ++项目属性(C ++ - >高级 - >调用约定)设置为__cdecl (/Gd)
。
导出的函数将使用哪种调用约定,如何确保它是约定?
答案 0 :(得分:5)
.def文件不控制调用约定,它完全由编译器决定。如果你没有在函数声明中显式使用__cdecl或__stdcall,那么它是编译器的默认值,所以__cdecl。对于C ++成员函数,角点案例是__thiscall,对于托管代码,是__clrcall。
调用约定还选择名称装饰样式,专门用于避免因客户端代码出错而发生意外。 __cdecl在名称前添加单个下划线,__ stdcall追加“@n”,其中n是堆栈激活帧的大小。当客户端代码使用错误的声明与参数的类型或数量不匹配时,这可以防止堆栈不平衡,这对于__stdcall来说是致命且非常难以诊断的问题。使用.def文件禁用此装饰实际上是一个坏主意,只有在使用LoadLibrary + GetProcAddress动态加载DLL时才应考虑使用。如果您打算让非C / C ++客户端使用您的DLL,那么明确使用__stdcall通常是个好主意,因为这往往是其他语言运行时的默认值。
对于64位代码而言,这一切都不重要,它幸福地只有一个调用约定。虽然通过添加__vectorcall调用约定看起来像Microsoft about to mess that up。