【问题标题】:how does extern "C" allow C++ code in a C file?extern "C" 如何在 C 文件中允许 C++ 代码?
【发布时间】:2016-08-15 13:45:09
【问题描述】:

为了在 C 文件中使用 C++ 代码,我读到我们可以执行 extern "C" { (where the c++ code goes here)},但是当我尝试使用 cout 打印某些内容时,我不断收到错误,因为它无法识别库。我想我只是对 extern "C" 如何允许您在 C 中使用 C++ 代码感到困惑。

【问题讨论】:

    标签: c++ extern-c


    【解决方案1】:

    情况正好相反。您可以使用 extern C 添加您想要使用 C++ 编译器编译为 C 代码的代码。

    除非我遗漏了一些你不能用 C 编译器编译 C++ 代码的东西。

    【讨论】:

      【解决方案2】:

      extern "C" 构造是特定于 C++ 的语法,没有 C 编译器能够理解它。

      这就是为什么您几乎总是会看到它与一些 conditional compilation 类似

      #ifdef __cplusplus
      extern "C" {
      #endif
      ...
      #ifdef __cplusplus
      }
      #endif
      

      extern "C" 的作用 只是为了禁止name mangling,这意味着在 C++ 源文件中定义的符号可以在 C 程序中使用。

      这让你可以拥有一个混合了 C 和 C++ 源代码的项目,并且 C 源代码可以调用已定义为 extern "C" 的 C++ 函数。

      非常简单,愚蠢的例子只是为了说明这一点:

      假设我们有一个用 C 编译器编译的 C 源文件:

      #include <stdio.h>
      
      void foo(void);  // Declare function prototype, so it can be called
      
      int main(void)
      {
          printf("Calling foo...\n");
          foo();
          printf("Done\n");
      
          return 0;
      }
      

      那么我们就有了foo函数的C++源文件:

      #include <iostream>
      
      extern "C" void foo()
      {
          std::cout << "Hello from foo\n";
      }
      

      C源文件用C编译器编译,C++源文件用C++编译器编译。然后将两个目标文件链接在一起形成可执行程序。因为foo 被定义为extern "C",所以它在目标文件中的符号名称没有被破坏,并且链接器可以从C 编译器创建的目标文件中解析引用。

      它也适用于另一个方向。因为 C 中的符号没有被破坏,所以 C++ 编译器需要知道这一点,这是通过声明 C 符号 extern "C" 来完成的,通常在头文件中使用如上所示的条件编译。如果不使用extern "C",C++ 编译器会认为这些符号是C++ 符号,并在链接器找不到被破坏的符号时破坏导致链接器问题的名称。

      同样愚蠢的例子:首先是一个 C++ 源文件

      #include <iostream>
      
      extern "C" void bar();  // Declare function prototype as an unmangled symbol
      
      int main()
      {
          std::cout << "Calling bar...\n";
          bar();
      }
      

      然后是C源文件

      #include <stdio.h>
      
      void bar(void)
      {
          printf("Inside bar\n");
      }
      

      【讨论】:

      • extern "C" 不仅仅是禁止名称修改。它还允许在 C 和 C++ 之间进行交互。
      • @彼得。还有什么其他事情(除了重载)?
      • @MadPhysicist - 很多事情。一个例子是extern "C" 函数可能使用与未指定为extern "C" 的函数不同的调用约定——这会影响参数的实际传递方式(例如,如果它们被压入堆栈,它们可能会以不同的顺序被压入——因此需要以不同的顺序检索才能在函数中使用)。另一个区别是任何声明为extern "C" 的东西都有外部链接。还有一些其他差异。
      • @彼得。感谢您的解释。这是否意味着我不能同时拥有 extern "C" 和有意义的内联?
      • @MadPhysicist - 这取决于你所说的“有意义的内联”是什么意思。 extern "C" 的一个目的是允许通过接口从 C 调用 C++ 代码(反之亦然),并且该边界将影响任一编译器是否内联 - 即使 C 和 C++ 编译器来自同一供应商,更是如此如果来自不同的供应商。
      【解决方案3】:

      extern "C" 是一种将 C 代码放入 C++ 代码的方式。更具体地说,它告诉编译器禁用某些功能,例如函数重载,以便它也可以关闭名称修饰。在 C++ 中,一个简单的函数如下:

      int add(int a, int b) {
          return a+b;
      }
      

      实际上会在库中获得一些时髦的名称来表示参数,这样如果您定义另一个函数,例如:

      double add(double a, double b) {
          return a+b;
      }
      

      它知道要调用哪一个。如果您尝试使用 C 库,那么您不希望这样,这就是 extern "C" 的用途。综上所述,extern "C" 不允许在 C 程序中使用 C++。

      【讨论】:

        【解决方案4】:

        由编译器生成的导出的 C++ 符号被修改以包含有关链接器的符号的附加类型信息。

        因此,C++ 中的链接器可以区分以下重载函数,而不是 C:

        • int fn();
        • int fn(int);
        • int fn(char*);
        • int fn(char*) const;
        • int fn(const char*);

        extern "C" { ... } 语法允许在 C++ 代码中定义符号(或对 C 符号的引用)而不使用 mangling 规则. 这允许此类 C++ 代码与 C 库链接。

        【讨论】:

          猜你喜欢
          • 2019-12-22
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-02-29
          • 2011-07-17
          • 2010-11-24
          相关资源
          最近更新 更多