我是否需要一个extern“C”块来包含标准C头?

时间:2011-11-10 22:46:04

标签: c++ posix-api

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

例如:

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

6 个答案:

答案 0 :(得分:14)

系统C标头通常已包含extern "C"块,由#ifdef __cplusplus保护。这样,当编译为C ++时,函数会自动声明为extern "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

答案 1 :(得分:8)

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

<stdio.h><math.h>和其他标准C头的行为由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)中定义为宏的是在命名空间范围(3.3.5)内   namespace std。

因此,在C ++中使用(例如)printf的标准的,不推荐的,规范的方法是#include <cstdio>,然后调用std::printf

答案 2 :(得分:2)

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

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

答案 3 :(得分:1)

不,您应该使用C ++包装器标头(例如<cstdio>)。那些照顾你的一切。

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

ETA:值得注意的是,许多实现都会在.h文件中包含如下所示的包装器,这样您就可以自行完成。

#ifdef  __cplusplus
extern "C" {
#endif

#ifdef  __cplusplus
}
#endif

答案 4 :(得分:-1)

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

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

#ifdef __cplusplus
extern "C" {
...

答案 5 :(得分:-1)

我只是仔细检查了stdlib.h以获取GNU编译器,并且声明不使用extern“C”作为声明。

编辑:

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

那么包含旧标题会在std上声明_GLIBCPP_USE_NAMESPACES定义了吗?