协慌网

登录 贡献 社区

外部 “C” 在 C ++ 中有什么影响?

extern "C"放入 C ++ 代码究竟做了什么?

例如:

extern "C" {
   void foo();
}

答案

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”):

  • extern“C” 是一个链接规范
  • 每个编译器都需要提供 “C” 链接
  • 链接规范只应在命名空间范围内发生
  • 所有函数类型,函数名和变量名都有语言链接 请参阅 Richard 的注释:只有具有外部链接的函数名和变量名具有语言链接
  • 具有不同语言链接的两种函数类型是不同的类型,即使它们是相同的
  • 连接规格嵌套,内部确定最终的连接
  • 类成员忽略 extern“C”
  • 最多一个具有特定名称的函数可以具有 “C” 链接(无论命名空间如何)
  • extern“C” 强制函数具有外部链接(不能使其静止) 请参阅 Richard 的注释: 'static' 在'extern' 中 “C”' 有效; 如此声明的实体具有内部链接,因此没有语言链接
  • 从 C ++ 到在其他语言中定义的对象以及从其他语言在 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()来调用这些函数时,这很方便。