2011-11-10 52 views
9

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

例如:

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

刚刚发现这个问题与您的问题类似:[为什么我们需要在C++中使用extern“C”{#include }?](http://stackoverflow.com/questions/67894/why-do-we-need -extern -c-include-foo-h-in-c) – AusCBloke

回答

7

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>等,并且它们由部分17.4.1.2指定(3)C++标准,它说的:

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

除在第18至27条中注明,每个标题012xxcname的内容应与ISO/IEC 9899:1990编程语言C(第7章)或 中规定的 对应的标题name.h相同,即ISO/IEC:1990编程语言-C修正1:C完整性,(条款 7),如ap似乎通过包含。然而,在C++标准库 中,声明和定义(除了在C中定义为宏的名称 除外)位于名称空间标准的名称空间范围(3.3.5)内。

所以标准的,非弃用,典型的方式使用(例如)在printf C++是#include <cstdio>,然后调用std::printf

1

不,你应该使用C++封装报头(例如像<cstdio>)。那些照顾你的一切。

如果这是一个头没有这些,那么是的,你会想要把它们包装在extern "C" {}

ETA:值得注意的是,许多实现将在下面的.h文件中包含包装器,这样你就可以不用自己做。

#ifdef __cplusplus 
extern "C" { 
#endif 

#ifdef __cplusplus 
} 
#endif 
+0

值得注意的是''等标题在技术上将它们的定义放在'std'命名空间中。 (许多实现也将它们放在顶级命名空间中,但这不是标准所说的。) – Nemo

-1

一个好主意,让编译器知道,以便它可以作为C++编译时预计的C代码。你也可能会发现头文件本身包含extern "C" {作为守卫。

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

#ifdef __cplusplus 
extern "C" { 
... 
+0

*“让编译器知道,以便在编译为C++时能够期待C代码”* - 这不是什么'extern“ C“'做。它不会改变代码的解释。它甚至不适用于代码。它是一种语言链接指令,它指示编译器生成符合链接器对C语言要求的符号。它使C++代码可以从C中调用,但不会更改代码生成。 – IInspectable

+0

@IInspectable不是_“指示编译器生成与链接器期望的符号兼容的符号”_暗示它适用于代码,或者至少是代码的调用约定?它肯定会让编译器(以及连接器)知道一些东西。 – Tanz87

+0

@ Tanz87:它不会改变代码的生成。生成的目标代码与“extern”C“'是否相同。该指令仅适用于符号命名。它对调用约定没有影响。 – IInspectable

1

是的,你做的。然而,许多系统(特别是Linux)已经像你一样增加了一个extern "C"包围。请参阅(在Linux上)文件/usr/include/unistd.h/usr/include/features.h和在/usr/include/sys/cdefs.h中定义的宏__BEGIN_DECLS,并在许多Linux系统包含文件中使用。

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

11

系统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 
2

在我看来它的出口头文件的责任,用外部的“C “适当。

0

我刚刚检查了GNU编译器的stdlib.h,声明不使用extern“C”作为声明。

编辑:

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

所以包括旧标题将放在STD提供_GLIBCPP_USE_NAMESPACES声明定义?