【发布时间】:2016-08-15 13:45:09
【问题描述】:
为了在 C 文件中使用 C++ 代码,我读到我们可以执行 extern "C" { (where the c++ code goes here)},但是当我尝试使用 cout 打印某些内容时,我不断收到错误,因为它无法识别库。我想我只是对 extern "C" 如何允许您在 C 中使用 C++ 代码感到困惑。
【问题讨论】:
为了在 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 编译器能够理解它。
这就是为什么您几乎总是会看到它与一些 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++ 之间进行交互。
extern "C" 函数可能使用与未指定为extern "C" 的函数不同的调用约定——这会影响参数的实际传递方式(例如,如果它们被压入堆栈,它们可能会以不同的顺序被压入——因此需要以不同的顺序检索才能在函数中使用)。另一个区别是任何声明为extern "C" 的东西都有外部链接。还有一些其他差异。
extern "C" 的一个目的是允许通过接口从 C 调用 C++ 代码(反之亦然),并且该边界将影响任一编译器是否内联 - 即使 C 和 C++ 编译器来自同一供应商,更是如此如果来自不同的供应商。
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 库链接。
【讨论】: