为了在 C 文件中使用 C++ 代码,我读到我们可以这样做extern "C" { (where the c++ code goes here)}
,但是当我尝试使用 cout 打印一些东西时,我不断收到错误,因为它无法识别库。我想我只是对 extern "C" 如何允许您在 C 中使用 C++ 代码感到困惑。
4 回答
反之亦然。您可以使用 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 源文件:
#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++ 代码中的方法。更具体地说,它告诉编译器禁用某些功能,例如函数重载,以便它也可以关闭名称修饰。在 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 库链接。