extern“C” 使得 C ++ 中的函数名称具有 “C” 链接(编译器不会破坏名称),以便客户端 C 代码可以使用仅包含 “C” 兼容头文件来链接(即使用)您的函数。声明你的功能。您的函数定义包含在二进制格式(由 C ++ 编译器编译)中,客户端 “C” 链接器将使用 “C” 名称链接到该格式。
由于 C ++ 有函数名称的重载而 C 没有,因此 C ++ 编译器不能只使用函数名作为链接的唯一 id,因此它通过添加有关参数的信息来破坏名称。 AC 编译器不需要破坏名称,因为您不能在 C 中重载函数名。当您声明函数在 C ++ 中具有 extern“C” 链接时,C ++ 编译器不会将参数 / 参数类型信息添加到用于的名称连锁。
您知道,您可以明确指定每个单独的声明 / 定义的 “C” 链接,或使用块将一系列声明 / 定义分组以具有特定的链接:
extern "C" void foo(int);
extern "C"
{
void g(char);
int i;
}
如果您关心技术细节,它们列在 C ++ 03 标准的 7.5 节中,这里是一个简短的摘要(重点是 extern“C”):
只是想添加一些信息,因为我还没有看到它发布。
您经常会在 C 标头中看到代码,如下所示:
#ifdef __cplusplus
extern "C" {
#endif
// all of your legacy C code here
#ifdef __cplusplus
}
#endif
这实现了它允许您将 C 头文件与 C ++ 代码一起使用,因为将定义宏 “__cplusplus”。但是你也可以仍然使用旧的 C 代码,在宏没有定义使用它,所以它不会看到独特的 C ++ 构建。
虽然,我也看过 C ++ 代码,例如:
extern "C" {
#include "legacy_C_header.h"
}
我想象的完成了同样的事情。
不确定哪种方式更好,但我已经看到了两种方式。
在每个 C ++ 程序中,所有非静态函数都在二进制文件中表示为符号。这些符号是特殊文本字符串,用于唯一标识程序中的函数。
在 C 中,符号名称与函数名称相同。这是可能的,因为在 C 中没有两个非静态函数可以具有相同的名称。
因为 C ++ 允许重载并且具有 C 不具备的许多功能 - 比如类,成员函数,异常规范 - 所以不可能简单地使用函数名作为符号名。为了解决这个问题,C ++ 使用了所谓的名称修改,它将函数名称和所有必要信息(如参数的数量和大小)转换为仅由编译器和链接器处理的奇怪字符串。
因此,如果您将函数指定为 extern C,则编译器不会对其执行名称修改,并且可以使用其符号名称作为函数名称直接访问它。
使用dlsym()
和dlopen()
来调用这些函数时,这很方便。