Ber*_*ron 47
extern "C"用于确保后面的符号没有被修饰(装饰).
例:
假设我们在一个名为的文件中有以下代码test.cpp:
extern "C" {
int foo() {
return 1;
}
}
int bar() {
return 1;
}
Run Code Online (Sandbox Code Playgroud)
如果你跑 gcc -c test.cpp -o test.o
看看符号名称:
00000010 T _Z3barv
00000000 T foo
foo() 保守名字.
Cth*_*utu 25
让我们看一下可以在C和C++中编译的典型函数:
int Add (int a, int b)
{
return a+b;
}
Run Code Online (Sandbox Code Playgroud)
现在在C中,该函数在内部称为"_Add".而使用名为name-mangling的系统在内部完全不同地调用C++函数.它基本上是一种命名函数的方法,以便具有不同参数的相同函数具有不同的内部名称.
因此,如果在add.c中定义了Add(),并且你在add.h中有原型,那么如果你试图在一个C++文件中包含add.h,你就会遇到问题.因为C++代码正在寻找名称与add.c中的名称不同的函数,所以会出现链接器错误.要解决该问题,您必须通过此方法包含add.c:
extern "C"
{
#include "add.h"
}
Run Code Online (Sandbox Code Playgroud)
现在,C++代码将链接到_Add而不是C++名称的版本.
这是表达式的一个用途.最重要的是,如果你需要在C++程序中编译严格的C代码(通过include语句或其他方法),你需要用extern"C"{...}声明来包装它.
当您使用extern"C"标记代码块时,您告诉系统使用C样式链接.
这主要影响链接器破坏名称的方式.您可以从链接器中获得标准的C风格命名,而不是使用C++样式名称修改(支持运算符重载更复杂).
在C++中,函数的名称/符号实际上被重命名为其他类,以便不同的类/名称空间可以具有相同签名的函数.在C中,功能全局定义,不需要这样的自定义重命名过程.
为了使C++和C相互通信,"extern C"指示编译器不要使用C约定.
extern C 影响 C++ 编译器的名称修改。它是一种让 C++ 编译器不破坏名称的方法,或者更确切地说,以与 C 编译器相同的方式破坏名称。这就是 C 和 C++ 的接口方式。
举个例子:
extern "C" void foo(int i);
Run Code Online (Sandbox Code Playgroud)
将允许该函数在 C 模块中实现,但允许从 C++ 模块中调用它。
当试图让 C 模块调用 C++ 模块中定义的 C++ 函数(显然 C 不能使用 C++ 类)时,就会出现麻烦。C 编译器不喜欢extern "C".
所以你需要使用这个:
#ifdef __cplusplus
extern "C" {
#endif
void foo(int i);
#ifdef __cplusplus
}
#endif
Run Code Online (Sandbox Code Playgroud)
现在,当它出现在头文件中时,C 和 C++ 编译器都会对该声明感到满意,并且现在可以在 C 或 C++ 模块中定义它,并且可以由 C 和 C++ 代码调用。
应该注意,extern "C"还修改了函数的类型.它不仅修改较低级别的内容:
extern "C" typedef void (*function_ptr_t)();
void foo();
int main() { function_ptr_t fptr = &foo; } // error!
Run Code Online (Sandbox Code Playgroud)
类型&foo不等于typedef指定的类型(尽管代码被某些编译器接受,但并非所有编译器都接受).