为什么我们在 C 中需要 extern "C"{ #include <foo.h> } ?

新手上路,请多包涵

为什么我们需要使用:

 extern "C" {
#include <foo.h>
}

具体来说:

  • 我们应该什么时候使用它?

  • 在需要我们使用它的编译器/链接器级别发生了什么?

  • 这在编译/链接方面如何解决需要我们使用它的问题?

原文由 Landon 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 838
2 个回答

C 和 C++ 表面上相似,但各自编译成一组非常不同的代码。当您在 C++ 编译器中包含头文件时,编译器需要 C++ 代码。但是,如果它是 C 头文件,则编译器期望头文件中包含的数据被编译成某种格式——C++ ‘ABI’ 或“应用程序二进制接口”,因此链接器会阻塞。这比将 C++ 数据传递给需要 C 数据的函数更可取。

(要深入了解,C++ 的 ABI 通常会“破坏”它们的函数/方法的名称,因此调用 printf() 而不将原型标记为 C 函数,C++ 实际上会生成代码调用 _Zprintf ,最后加上额外的废话。)

所以:使用 extern "C" {...} 当包含 ac 标头时,就这么简单。否则,您将在编译的代码中出现不匹配,并且链接器会阻塞。然而,对于大多数头文件,您甚至不需要 extern 因为大多数系统 C 头文件已经考虑到它们可能包含在 C++ 代码中并且已经 extern "C" 他们的代码.

原文由 gnkdl_gansklgna 发布,翻译遵循 CC BY-SA 4.0 许可协议

任何时候你都应该使用 extern “C”,只要你包含一个定义函数的头文件,这个函数驻留在由 C 编译器编译的文件中,用于 C++ 文件。 (许多标准 C 库可能会在其头文件中包含此检查,以使开发人员更简单)

例如,如果您有一个包含 3 个文件 util.c、util.h 和 main.cpp 的项目,并且 .c 和 .cpp 文件都是使用 C++ 编译器(g++、cc 等)编译的,那么它不是t 确实需要,甚至可能导致链接器错误。如果您的构建过程对 util.c 使用常规 C 编译器,那么在包含 util.h 时您将需要使用 extern “C”。

正在发生的事情是 C++ 在其名称中对函数的参数进行了编码。这就是函数重载的工作原理。 C 函数往往会在名称的开头添加下划线(“_”)。如果函数的实际名称是 _DoSomething() 或只是 DoSomething(),则不使用 extern “C” 链接器将寻找名为 DoSomething@@int@float() 的函数。

使用 extern “C” 通过告诉 C++ 编译器它应该寻找一个遵循 C 命名约定而不是 C++ 的函数来解决上述问题。

原文由 HitScan 发布,翻译遵循 CC BY-SA 2.5 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题