__cdecl or __stdcall on Windows?
__cdecl or __stdcall on Windows?
我目前正在为Windows开发一个C++库,该库将作为DLL分发。我的目标是最大限度地提高二进制互操作性;更准确地说,我的DLL中的函数必须可以从使用多个版本的MSVC++和MinGW编译的代码中使用,而无需重新编译DLL。然而,我对cdecl
和stdcall
哪个调用约定最好感到困惑。
有时我会听到这样的陈述:;C调用约定是唯一一个保证是相同的"交叉编译器";,这与诸如";cdecl
的解释有一些变化,特别是在如何返回值"方面;。这似乎并没有阻止某些库开发人员(如libsndfile)在他们分发的DLL中使用C调用约定,而不会出现任何明显的问题。
另一方面,stdcall
调用约定似乎定义明确。据我所知,所有Windows编译器基本上都必须遵循它,因为这是Win32和COM使用的约定。这是基于这样一种假设,即没有Win32/COM支持的Windows编译器将不会很有用。论坛上发布的许多代码片段都将函数声明为stdcall
,但我似乎找不到一篇文章能清楚地解释为什么。
有太多相互矛盾的信息,我进行的每一次搜索都会给我不同的答案,这并不能真正帮助我在两者之间做出决定。我正在寻找一个清晰、详细、有争议的解释,解释为什么我应该选择一个而不是另一个(或者为什么两者相等)。
注意,这个问题不仅适用于";经典的";函数,但也可以调用虚拟成员函数,因为大多数客户端代码将通过"与我的DLL接口;接口";,纯虚拟类(以下模式描述,例如这里和那里)。
我刚刚做了一些真实世界的测试(使用MSVC++和MinGW编译DLL和应用程序,然后将它们混合)。看起来,我使用cdecl
调用约定得到了更好的结果。
更具体地说:stdcall
的问题是MSVC++篡改DLL导出表中的名称,即使在使用extern "C"
时也是如此。例如,foo
变为_foo@4
。这种情况仅在使用__declspec(dllexport)
时发生,而不是在使用DEF文件时发生;然而,在我看来,DEF文件是一个维护麻烦,我不想使用它们。
MSVC++名称篡改带来了两个问题:
- 在DLL上使用
GetProcAddress
会稍微复杂一些 - 默认情况下,MinGW不会在修饰名称前加上不需要的前缀(例如,MinGW将使用
foo@4
而不是_foo@4
),这会使链接变得复杂。此外,它还引入了看到DLL和应用程序的"非下划线版本"在野外弹出的风险,这些版本与"下划线版本"不兼容
我尝试过cdecl
约定:MSVC++和MinGW之间的互操作性非常好,开箱即用,并且名称在DLL导出表中保持未修饰状态。它甚至适用于虚拟方法。
由于这些原因,cdecl
显然是我的赢家。
这两种调用约定的最大区别在于,"__cdecl"在函数调用后将平衡堆栈的负担放在了调用者身上,这允许函数具有可变数量的参数。"__stdcall"约定本质上"更简单",但在这方面灵活性较差。
此外,我认为托管语言默认情况下使用stdcall约定,因此如果使用cdecl,任何在其上使用p/Invoke的人都必须明确声明调用约定。
所以,如果所有的函数签名都是静态定义的,我可能会倾向于stdcall,如果不是cdecl的话。
就安全性而言,__cdecl
约定"更安全",因为它是需要释放堆栈的调用方。__stdcall
库中可能发生的情况是,开发人员可能忘记正确释放堆栈,或者攻击者可能会通过损坏DLL的堆栈(例如,通过API挂钩)注入一些代码,而调用方随后不会检查该堆栈。我没有任何CVS安全示例表明我的直觉是正确的。
- SFML 交叉编译 for Windows on Linux.
- Cmake with Flex/Bison on windows
- Boost::process on Windows - with MinGW?
- anaconda cythonize C++ on windows 10
- CMake & MinGW Compileilation on Windows,无需 -G "MinGW Makefiles"标志
- Windows Machine Learning (winML) on ARM
- 用于Clang on Windows的CMake生成器
- boost::stacktrace on Windows MSVS 2017
- TLS with http_listener in Microsoft cpprestsdk on Windows
- DirectX 11 on Windows 10
- CppFlow on windows 10
- OpenMP 4.5 on Windows with Clang, CMake & Ninja
- SDL 2.0.7 touch on Windows
- C++ on Jupyter Notebook for Windows
- WinHttpSendRequest and HTTPS on Windows XP
- OpenSSL on Windows and Visual Studio 2010
- 在 Windows for Linux on Intel 上编译C++库
- OpenCV on eclipse on windows
- C++ [[gnu::visibility( "default" )]] vs __declspec(dllexport) on Windows 和 Linux
- endian.h on Windows