【问题标题】:When is "extern C " necessary in c++ in windows?什么时候在 Windows 中的 c++ 中需要“extern C”?
【发布时间】:2010-09-16 17:07:50
【问题描述】:

我们知道我们可以直接在c++中使用c函数,那么什么时候需要extern "C"呢?

【问题讨论】:

    标签: c++ c windows


    【解决方案1】:

    如果您的函数是在 .c 文件中实现的,则 .cpp 文件将需要 extern "C" 引用,否则它们会引用一个损坏的 C++ 样式的函数名,并且链接会失败。

    从 DLL 中导出函数也很方便,这样它们就可以以未损坏的名称导出。

    【讨论】:

    • 这个答案是正确但不完整的,就像@Randolpho 的答案一样,也是正确但不完整的。整个答案将是两者的总和。
    【解决方案2】:

    C++ 函数必须由C 代码而不是C++ 代码调用时,这是必要的。

    基本上,当您希望您的 C++ 库向后兼容时。

    【讨论】:

    • 不,不,不……呃!如果项目是C,请不要将C++ 添加到其中:将其转换为C++,如果需要,将C 添加到C++ 项目。 或者(更好的恕我直言)将其保留在 C 中并完全避免 C++
    • 这个答案是正确但不完整的,就像@Graham Perks 的答案一样,也是正确但不完整的。整个答案将是两者的总和。
    • @pmg:即使您的库是用 C++ 开发的,您也可能不拥有 C 项目或无法更改他们想要的界面
    • @pmg:想想外部库和回调。
    • @pmg:为什么不完全避免 C 而只使用 program with butterflies
    【解决方案3】:

    extern "C" 有两种截然不同的用途。一种是在 C++ 中定义一个应该能够从 C 调用的函数。即,你正在用 C++ 编写代码,但它需要与 C 代码交互。在这种情况下,您将函数定义extern "C"

    extern "C" {
        int c_callable_func1() {}
        int c_callable_func2() {}
    }
    

    当您这样做时,这些函数的接口必须遵循与 C 中几乎相同的规则(例如,您不能重载函数或对任何参数使用默认值)。

    另一种(相当常见的)情况是您有用 C 编写的代码,您希望能够从 C++ 调用。在这种情况下,函数定义 与以前完全相同,但需要将函数声明/原型化为extern "C"。在典型情况下,您希望在 C 或 C++ 文件中使用可以是 #included 的单个标头,因此结构如下所示:

    // myheader.h
    #ifndef MY_HEADER_H_INCLUDED_
    #define MY_HEADER_H_INCLUDED_
    
    #ifdef __cplusplus
    extern "C" {
    #endif
    
        int func1(void);
        void func2(int);
    
    #ifdef __cplusplus
    }
    #endif
    
    #endif
    

    因此,C++ 编译器会看到被extern "C" 块包围的函数声明(和typedefs 等),而C 编译器会看到原型,而不是被它无法识别的东西包围。

    在第一种情况下(可从 C 调用的 C++ 函数),您通常会以大致相同的方式构建标头,因此您也可以在必要时从 C++ 调用这些函数(但在接口处,您仍然会丢失所有额外的功能类似 C++ 的函数重载)。

    【讨论】:

      【解决方案4】:

      如您所知,c++ 支持函数重载,它使用不同的参数多次定义相同的函数或方法。为此,编译器必须为每个符号添加一些符号...例如,编译器将在以下声明中更改函数名称 foo 来自

      void foo(int f,char c);
      

      foo@i&c
      

      不幸的是,C 不支持这一点。编译后所有函数名称保持不变。所以,要从 c 中调用 c++ 函数,你必须知道修改后的确切名称,我认为这很难,而且从一个编译器到另一个编译器是不同的。

      要解决这个问题并能够从 c 调用 c++ 函数并阻止编译器更改您必须使用此关键字的名称,例如

      extern "C" { 
      void foo(int f,char c);
      }
      

      就是这样!!!

      【讨论】:

      • +1 为了清楚地解释原因,但这也发生在相反的方向:如果您在库中有一个 C 函数,并且包含没有 extern "C" 限定符的标头,则 c++编译器将破坏符号。然后在链接阶段,它将尝试定位损坏的符号,但会失败,因为 c 编译器在编译 C 代码时没有损坏名称。
      【解决方案5】:

      因为 C 和 C++ 编译器生成的函数签名不同 - 即使在使用 C++ 时,这也会为 C 函数设置 C 约定。

      【讨论】:

        猜你喜欢
        • 2012-12-05
        • 2011-07-07
        • 2017-08-17
        • 2011-04-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-12-26
        相关资源
        最近更新 更多