外部"C"如何允许在 C 文件中C++代码?

how does extern "C" allow C++ code in a C file?

本文关键字:C++ 代码 何允许 外部 文件      更新时间:2023-10-16

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

事实正好相反。 可以使用 extern C 将要编译的代码添加为使用 C++ 编译器的 C 代码。

除非我缺少某些内容,否则您无法使用 C 编译器编译C++代码。

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

这就是为什么你几乎总是会看到它与一些条件编译配对,比如

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

extern "C"所做的只是禁止名称重整,这意味着在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("Donen");
    return 0;
}

然后我们有一个foo函数的C++源文件:

#include <iostream>
extern "C" void foo()
{
    std::cout << "Hello from foon";
}
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 barn");
}
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++。

导出的

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 库链接。