Eti*_*mps 76 c++ windows dll calling-convention binary-compatibility
我目前正在开发一个Windows的C++库,它将作为DLL发布.我的目标是最大化二进制互操作性; 更确切地说,我的DLL中的函数必须可以从使用多个版本的MSVC++和MinGW编译的代码中使用,而无需重新编译DLL.但是,我对哪种调用约定是最好的cdecl或者很困惑stdcall.
有时我会听到诸如"C调用约定是唯一一个保证编译器相同的语句"的陈述,这与诸如" 解释中存在一些变化cdecl,特别是如何返回值 "之类的陈述形成对比.这似乎并没有阻止某些库开发人员(如libsndfile)在他们分发的DLL中使用C调用约定,而没有任何明显的问题.
另一方面,stdcall调用约定似乎是明确定义的.据我所知,所有Windows编译器基本上都需要遵循它,因为它是用于Win32和COM的约定.这是基于这样的假设:没有Win32/COM支持的Windows编译器不会非常有用.在论坛上发布的很多代码片段都声明了函数,stdcall但我似乎无法找到一个明确解释原因的帖子.
那里有太多相互矛盾的信息,我运行的每一次搜索都给出了不同的答案,这些答案并没有真正帮助我在两者之间作出决定.我正在寻找一个清晰,详细,有争议的解释,为什么我应该选择一个而不是另一个(或者为什么两者是等价的).
请注意,这个问题不仅适用于"经典"函数,还适用于虚拟成员函数调用,因为大多数客户端代码将通过"接口",纯虚拟类(以下描述的模式,例如此处和那里)与我的DLL接口.
Eti*_*mps 74
我刚做了一些真实的测试(用MSVC++和MinGW编译DLL和应用程序,然后混合它们).看来,我对cdecl调用约定有更好的结果.
更具体地说:问题stdcall是即使在使用时,MSVC++也会破坏DLL导出表中的名称extern "C".例如foo变成_foo@4.这只在使用__declspec(dllexport)时发生,而不是在使用DEF文件时; 但是,在我看来,DEF文件是一个维护麻烦,我不想使用它们.
MSVC++名称修改带来两个问题:
GetProcAddress在DLL上使用变得稍微复杂一些;foo@4而不是_foo@4),这会使链接复杂化.此外,它还引入了看到"非下划线版本"的DLL和应用程序的风险,这些版本与"下划线版本"不兼容.我已经尝试了这个cdecl惯例:MSVC++和MinGW之间的互操作性完美,开箱即用,并且名称在DLL导出表中保持未修饰.它甚至适用于虚拟方法.
由于这些原因,cdecl对我来说是一个明显的赢家.
Bra*_*etz 17
两个调用约定的最大区别在于" _ _cdecl"在调用者调用函数之后放置了平衡堆栈的负担,这允许函数具有可变数量的参数."__stdcall"惯例本质上是"更简单"的,但在这方面却不那么灵活.
此外,我相信托管语言默认使用stdcall约定,因此任何使用P/Invoke的人都必须显式声明调用约定,如果你使用cdecl.
所以,如果你的所有函数签名都将被静态定义,我可能会倾向于stdcall,如果不是cdecl.
在安全性方面,__cdecl约定"更安全",因为调用者需要释放堆栈.__stdcall库中可能发生的事情是开发人员可能忘记正确释放堆栈,或者攻击者可能通过破坏DLL的堆栈(例如通过API挂钩)注入一些代码,然后调用者不会检查它.我没有任何CVS安全示例表明我的直觉是正确的.
| 归档时间: |
|
| 查看次数: |
47638 次 |
| 最近记录: |