【问题标题】:__cdecl and __declspec calling conventions confusion__cdecl 和 __declspec 调用约定混淆
【发布时间】:2011-10-18 09:45:48
【问题描述】:

我正在为第三方应用程序编写 DLL。主要软件工程师提到应用程序使用 __cdecl (/Gd) 调用约定。我需要确保我使用它。

另外,第三方给我提供了一个C++ DLL骨架,它导出的函数如下:

#ifdef _EXPORTING
  #define DECLSPEC    __declspec(dllexport)
#else
   #define DECLSPEC    __declspec(dllimport)
#endif

#ifdef __cplusplus
   extern "C" {  
#endif

DECLSPEC int ICD_Create(char* id);
....
....

我有点困惑。为什么使用 __declspec 约定而不是 __cdedl 导出函数? __declspec 是否支持 _cdecl?

谢谢。

【问题讨论】:

    标签: c++ c dllimport calling-convention


    【解决方案1】:

    __declspec()__cdecl 正在解决调用函数的两个不同方面,您可以(在这种情况下,您应该)同时使用两者。

    __cdecl指定调用约定,指定参数如何通过栈传递给函数,非常重要的是,之后谁清理栈(__cdecl的情况下是调用者整理)。

    __declspec(dllimport/dllexport) 用于简化从 DLL 导出函数定义:您不需要使用它们,但其他导出函数的方式相当笨拙。

    显式使用__cdecl 可能是一个好主意,而不是执行您已经完成的代码 sn-p 操作,这依赖于编译器来选择调用约定。你可以用我认为的命令行开关覆盖它,我相信默认值会根据你是编译 C 还是 C++ 代码而有所不同,所以更明确(像往常一样)更好。

    【讨论】:

    • 那么,我在哪里指定调用约定。我的印象是它被指定为int __cdecl VB_Create(char *)。对吗?
    • 太好了,调用约定的分配是在编译器中还是在链接器中?在我看来,两者都涉及。是这样吗?
    • @Peretz,在你的情况下,你最终会得到类似 int DECLSPEC __cdecl VB_Create(char*) 的东西。
    • @Peretz - 你的第二个问题,我认为实际上只有编译器需要担心调用约定,因为它生成的代码会将参数加载到堆栈上,调用函数,检索返回值,并整理堆栈:调用约定控制该代码的位置以及放入的顺序。链接器只需担心函数地址是什么并正确处理。
    • extern "C" 位不暗示__cdecl
    【解决方案2】:

    这些是正交概念。 __declspec 仅表示相关实体的“存储类”。在您正在查看的上下文中,它会告诉您是否正在指定导入或导出函数(这通常是使用可以作为 DLL 的一部分构建或直接包含在可执行文件中的代码时出现的问题,具体取决于上下文)。

    有关__declspec 的更多信息是here

    __cdecl 调用约定表明该函数使用传统的“C”语言约定来传递参数。还有其他样式,尤其是__stdcall

    有关__cdecl__stdcall(和其他)的更多详细信息是here

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-10-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多