34

也许我不了解 C 和 C++ 之间的区别,但是我们何时以及为什么需要使用

extern "C" {

? 显然它是一个“链接约定”。

我简要地阅读了它,并注意到 MSVS 中包含的所有 .h 头文件都用它包围了它们的代码。究竟什么类型的代码是“C 代码”而不是“C++ 代码”?我以为 C++ 包含所有 C 代码?

我猜测情况并非如此,C++ 是不同的,标准特性/功能存在于其中之一但不是两者都存在(即:printf 是 C,cout 是 C++),但是 C++ 是向后兼容的,尽管外部“C”声明。这个对吗?

我的下一个问题取决于第一个问题的答案,但无论如何我都会在这里问:由于用 C 编写的 MSVS 头文件被 extern "C" { ... } 包围,你什么时候需要使用它自己在自己的代码中?如果您的代码是 C 代码并且您正尝试在 C++ 编译器中编译它,那么它不应该毫无问题地工作吗,因为您包含的所有标准 h 文件都已经在 C++ 编译器中包含了 extern "C" 的东西?

在 C++ 中编译但链接到已构建的 C 库或其他东西时,您是否必须使用它?

4

7 回答 7

37

声明在 C 中实现/编译的函数时,您需要extern "C"在 C++ 中使用。 的使用extern "C"告诉编译器/链接器使用 C 命名和调用约定,而不是 C++ 名称修改和 C++ 调用约定,否则将使用. 对于其他库提供的函数,您几乎不需要使用extern "C",因为编写良好的库已经为它导出到 C 和 C++ 的公共 API 提供了它。但是,如果您编写了一个希望在 C 和 C++ 中都可用的库,那么您必须有条件地将它放在头文件中。

至于是否所有的C代码都是C++代码……不,那是不正确的。C++ 是“C 的超集”是一个流行的神话。虽然 C++ 确实力求与 C 尽可能兼容,但也存在一些不兼容之处。例如,bool是有效的 C++ 但不是有效的 C,而_Bool在 C99 中存在,但在 C++ 中不可用。

至于您是否需要将 extern "C" 与系统的 ".h" 文件一起使用....任何精心设计的实现都会为您提供这些,因此您不需要使用它们。但是,为了确保提供了它们,您应该包含以“c”开头并省略“.h”的等效头文件。例如,如果您包含 <ctype.h>,几乎所有合理的系统都会添加 extern "C";但是,为了确保 C++ 兼容的标头,您应该包含标头 <cctype>。

您可能还对C++ FAQ Lite 中的混合 C 和 C++感兴趣。

于 2010-05-09T06:14:34.673 回答
21

其他答案是正确的,但一个完整的“样板”示例可能会有所帮助。在 C 和/或 C++ 项目中包含 C 代码的规范方法如下:

//
// C_library.h
//

#ifdef __cplusplus
extern "C" {
#endif

//
// ... prototypes for C_library go here ...
//

#ifdef __cplusplus
}
#endif

-

//
// C_library.c
//

#include "C_library.h"

//
// ... implementations for C_library go here ...
//

-

//
// C++_code.cpp
//

#include "C_library.h"
#include "C++_code.h"

//
// ... C++_code implementation here may call C functions in C_library.c ...
//

注意:以上内容也适用于从 Objective-C++ 调用 C 代码。

于 2010-05-09T06:58:11.930 回答
16

C++ 编译器对符号表中名称的处理方式与 C 编译器不同。您需要使用extern "C"声明来告诉 C++ 编译器在构建符号表时使用 C 修改约定。

于 2010-05-09T06:13:16.113 回答
3

我使用“extern c”,以便 C# 可以读取我的 C++ 代码,而不必弄清楚导出 C++ dll 函数时所做的额外名称修改。否则,为了正确访问 dll 中的 C++ 函数,我必须在 C# 端的函数入口点末尾添加额外的无意义(或实际上是非英语)字符。

于 2010-05-09T06:24:52.577 回答
3

extern "C" {}块告诉 C++ 编译器使用 C 命名和调用约定。如果您不使用它,如果尝试在 C++ 项目中包含 C 库,则会出现链接器错误,因为 C++ 会破坏名称。我倾向于在我的所有 C 头文件上使用它,以防它们曾经在 C++ 项目中使用过:

#ifdef __cplusplus
extern "C" {
#endif

/* My library header */

#ifdef __cplusplus
} // extern
#endif
于 2010-05-09T06:25:58.837 回答
2

extern "C"当您想在由 C++ 编译器编译的代码中使用 C 调用约定时,您需要使用。有两个原因:

  • 您有一个用 C 语言实现的函数,并希望从 C++ 调用它。

  • 您有一个用 C++ 实现的函数,并希望从 C 调用它。请注意,在这种情况下,您只能在函数接口中使用 C++ 的 C 部分(无类,...)。

除了 C 之外,当您想要在 C++ 和使用与 C 相同的调用和命名约定的其他语言之间进行互操作时,这也适用。

通常,C 头文件中的声明用

#ifdef __cplusplus
extern "C" {
#endif

[... C declarations ...]

#ifdef __cplusplus
}
#endif

使其可以从 C++ 中使用。

于 2010-05-09T06:37:22.330 回答
1

C++ 函数受名称修饰的影响。这使得它们无法直接从 C 代码调用,除非extern "C"使用。

于 2010-05-09T06:12:45.160 回答