2011-11-10 85 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聲明定義?