16

我是否需要一个extern "C" {}块来在 C++ 程序中包含标准 C 头文件。只考虑在 C++ 中没有对应的标准 C 头文件。

例如:

extern "C" {
 #include <fcntl.h>
 #include <unistd.h>
}
4

6 回答 6

21

系统 C 标头通常已经包含一个extern "C"块,由#ifdef __cplusplus. 这样,函数extern "C"在编译为 C++ 时会自动声明为,您无需手动执行此操作。

例如在我的系统上unistd.hfcntl.h以 开头__BEGIN_DECLS和结尾__END_DECLS,这些宏定义在sys/cdefs.h

/* C++ needs to know that types and declarations are C, not C++.  */
#ifdef   __cplusplus
# define __BEGIN_DECLS  extern "C" {                                            
# define __END_DECLS }
#else
# define __BEGIN_DECLS
# define __END_DECLS
#endif
于 2011-11-10T22:56:06.370 回答
10

<fcntl.h>标准未指定 C++ 中的and的行为<unistd.h>(因为它们也不是 C89 标准的一部分)。也就是说,我从未见过他们(a)存在并且(b)实际上需要包装在一个extern "C"块中的平台。

<stdio.h>、和其他标准 C 头文件的行为<math.h>由 C++03 标准的 D.5 节指定。它们不需要extern "C"包装块,它们将符号转储到全局命名空间中。但是,附件 D 中的所有内容均已“弃用”。

这些标头的规范 C++ 形式是<cstdio><cmath>等,它们由 C++ 标准的第 17.4.1.2 (3) 节指定,其中说:

<cassert> <ciso646> <csetjmp> <cstdio> <ctime> <cctype> <climits>
<csignal> <cstdlib> <cwchar> <cerrno> <clocale> <cstdarg> <cstring>
<cwctype>

除了第 18 到 27 节中的说明外,每个头文件 cname 的内容应与相应头文件 name.h 的内容相同,如 ISO/IEC 9899:1990 编程语言 C(第 7 条)或 ISO/IEC 中规定的:1990 编程语言—C 修正案 1:C 完整性,(第 7 条),视情况而定,如同包含在内。然而,在 C++ 标准库中,声明和定义(在 C 中定义为宏的名称除外)在命名空间 std 的命名空间范围 (3.3.5) 内。

printf因此,在 C++ 中使用(例如)的标准、非弃用、规范方式是 to#include <cstdio>然后调用std::printf.

于 2011-11-10T23:00:48.597 回答
2

是的你是。但是,许多系统(尤其是 Linux)已经extern "C"像您一样添加了括号。请参阅(在 Linux 上)文件和在许多 Linux 系统包含文件中定义和使用/usr/include/unistd.h /usr/include/features.h的宏 。__BEGIN_DECLS/usr/include/sys/cdefs.h

所以在 Linux 上,你通常可以避免你的extern "C",但它不会有害(并且,恕我直言,在这种情况下提高可读性)。

于 2011-11-10T22:54:47.910 回答
1

不,您应该使用 C++ 包装头文件(例如 like <cstdio>)。那些会为你处理所有这些。

如果它是一个没有这些的标题,那么是的,您需要将它们包装在extern "C" {}.

ETA:值得注意的是,许多实现将在 .h 文件中包含包装器,如下所示,这样您就可以不用自己动手了。

#ifdef  __cplusplus
extern "C" {
#endif

#ifdef  __cplusplus
}
#endif
于 2011-11-10T22:51:12.657 回答
-1

最好让编译知道,以便在编译为 C++ 时可以预期 C 代码。您可能还会发现头文件本身包含extern "C" {作为警卫。

例如,curses.h在我的系统上包含:

#ifdef __cplusplus
extern "C" {
...
于 2011-11-10T22:53:31.500 回答
-1

我只是仔细检查了 GNU 编译器的 stdlib.h 并且声明不使用 extern "C" 作为声明。

编辑:

if defined __cplusplus && defined _GLIBCPP_USE_NAMESPACES
define __BEGIN_NAMESPACE_STD    namespace std {

因此,如果 _GLIBCPP_USE_NAMESPACES 已定义,包括旧标题将在 std 上放置声明?

于 2011-11-10T22:58:23.343 回答