Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/141.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
__Windows上的cdecl或u stdcall? 我正在开发一个Windows的C++库,它将作为DLL分发。我的目标是最大化二进制互操作性;更准确地说,我的DLL中的函数必须可以从使用多个版本的MSVC++和MinGW编译的代码中使用,而无需重新编译DLL。然而,我不知道哪种呼叫约定是最好的,或者_C++_Windows_Dll_Calling Convention_Binary Compatibility - Fatal编程技术网

__Windows上的cdecl或u stdcall? 我正在开发一个Windows的C++库,它将作为DLL分发。我的目标是最大化二进制互操作性;更准确地说,我的DLL中的函数必须可以从使用多个版本的MSVC++和MinGW编译的代码中使用,而无需重新编译DLL。然而,我不知道哪种呼叫约定是最好的,或者

__Windows上的cdecl或u stdcall? 我正在开发一个Windows的C++库,它将作为DLL分发。我的目标是最大化二进制互操作性;更准确地说,我的DLL中的函数必须可以从使用多个版本的MSVC++和MinGW编译的代码中使用,而无需重新编译DLL。然而,我不知道哪种呼叫约定是最好的,或者,c++,windows,dll,calling-convention,binary-compatibility,C++,Windows,Dll,Calling Convention,Binary Compatibility,有时我会听到这样的语句“C调用约定是唯一一个保证相同的accross编译器”,这与诸如“”之类的语句形成了对比。这似乎并没有阻止某些库开发人员(比如)在他们分发的DLL中使用C调用约定,而没有任何明显的问题 另一方面,stdcall调用约定似乎定义得很好。据我所知,所有Windows编译器基本上都需要遵循它,因为它是Win32和COM使用的约定。这是基于这样的假设,即没有Win32/COM支持的Windows编译器将不会非常有用。论坛上发布的许多代码片段都将函数声明为stdcall,但我似乎找不

有时我会听到这样的语句“C调用约定是唯一一个保证相同的accross编译器”,这与诸如“”之类的语句形成了对比。这似乎并没有阻止某些库开发人员(比如)在他们分发的DLL中使用C调用约定,而没有任何明显的问题

另一方面,
stdcall
调用约定似乎定义得很好。据我所知,所有Windows编译器基本上都需要遵循它,因为它是Win32和COM使用的约定。这是基于这样的假设,即没有Win32/COM支持的Windows编译器将不会非常有用。论坛上发布的许多代码片段都将函数声明为
stdcall
,但我似乎找不到一篇文章能够清楚地解释原因

那里有太多相互冲突的信息,我运行的每个搜索都会给我不同的答案,这并不能真正帮助我在两者之间做出决定。我正在寻找一个清晰、详细、有争议的解释,解释为什么我应该选择一个而不是另一个(或者为什么两者是等价的)


请注意,这个问题不仅适用于“经典”函数,也适用于虚拟成员函数调用,因为大多数客户端代码将通过“接口”、纯虚拟类(如和所述的模式)与我的DLL进行接口。

两种调用约定的最大区别是“\uu cdecl”将平衡堆栈的负担放在调用方的函数调用之后,这允许函数具有可变数量的参数。“_stdcall”公约在性质上是“简单的”,但在这方面不太灵活

另外,我认为托管语言默认使用stdcall约定,因此,如果使用cdecl,任何在其上使用p/Invoke的人都必须显式地声明调用约定


因此,如果所有函数签名都是静态定义的,我可能会倾向于stdcall,如果不是cdecl。

我只是做了一些实际测试(用MSVC++和MinGW编译DLL和应用程序,然后混合它们)。看起来,我使用
cdecl
调用约定获得了更好的结果

更具体地说:
stdcall
的问题是MSVC++会损坏DLL导出表中的名称,即使在使用
extern“C”
时也是如此。例如
foo
变成
_foo@4
。这仅在使用
\uuu declspec(dllexport)
时发生,而不是在使用DEF文件时发生;然而,在我看来,DEF文件是一个维护麻烦,我不想使用它们

MSVC++名称损坏带来两个问题:

  • 在DLL上使用会变得稍微复杂一些
  • 默认情况下,MinGW不会在修饰名称前加上未加分数(例如,MinGW将使用
    foo@4
    而不是
    _foo@4
    ),这会使链接复杂化。此外,它还带来了看到DLL的“非下划线版本”以及在野外弹出的与“下划线版本”不兼容的应用程序的风险
我尝试了
cdecl
约定:MSVC++和MinGW之间的互操作性非常好,开箱即用,并且名称在DLL导出表中保持不变。它甚至适用于虚拟方法


基于这些原因,
cdecl
显然是我的赢家。

就安全性而言,
\uu cdecl
约定是“更安全的”,因为调用方需要释放堆栈。在
\uu stdcall
库中可能发生的情况是,开发人员可能忘记了正确释放堆栈,或者攻击者可能会通过破坏DLL的堆栈(例如通过API挂钩)而注入一些代码,调用方随后不会检查这些堆栈。
我没有任何CVS安全示例表明我的直觉是正确的。

“cdecl的解释有一些变化,特别是在如何返回值方面”-这大致意味着在x86上使用cdecl的不同操作系统可能会使用不同的cdecl变体,即他们都称为“cdecl”的不同ABI。Windows锁定了变体,任何在Windows上运行且不尊重Windows选择的实现都无法调用Windows cdecl函数,因此正如您所说的stdcall,它对Windows编程毫无用处,还有一些标准的C函数很难实现。调用Win32 API函数时使用了u stdcall调用约定。值得注意的是,这并不适用于64位DLL,因为通常都忽略了O.StdCalk和Ay-CCDL,因此在导出的C函数上没有名字命名。@ JTBR如何导出导出的C++函数(即,没有<代码>外)C“< /COD>”?@ ELA782C++总是有一些名称的修饰,以便支持函数重载。但这不是标准化的,因此编译器之间可能会有所不同。@jtbr对不起,我不是指mangling这个名字。我的意思是,在输出C++功能的64位DLL中,是否也忽略了Ay-StdCalk和Ay-CCDL。我相信在所有x86-64编译中都会忽略u stdcall和u cdecl。看见