2011-11-10 12 views
9

Ho bisogno di un blocco extern "C" {} per includere intestazioni C standard in un programma C++. Considera solo le intestazioni C standard che non hanno controparti in C++.Ho bisogno di un blocco "C" esterno per includere intestazioni C standard?

Ad esempio:

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

Ho appena trovato questa domanda simile alla tua: [Perché abbiamo bisogno di una "C" esterna {#include } in C++?] (Http://stackoverflow.com/questions/67894/why-do-we-need -extern-c-include-foo-h-in-c) – AusCBloke

risposta

7

Il comportamento di <fcntl.h> e <unistd.h> in C++ non è specificato dallo standard (perché anch'essi non fanno parte dello standard C89). Detto questo, non ho mai visto una piattaforma in cui (a) esiste e (b) in realtà ha bisogno di essere avvolto in un blocco extern "C".

Il comportamento di <stdio.h>, <math.h> e le altre intestazioni C standard è specificato dalla sezione D.5 dello standard C++ 03. Non richiedono un blocco wrapper extern "C" e riversano i loro simboli nello spazio dei nomi globale. Tuttavia, tutto nell'Allegato D è "deprecato".

La canonica C++ sotto forma di queste intestazioni è <cstdio>, <cmath>, ecc, e sono specificati dalla sezione 17.4.1.2 (3) dello standard C++, che dice:

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

Salvo come indicato nelle clausole da 18 a 27, il contenuto di ciascuna intestazione cname deve essere uguale a quello dell'intestazione corrispondente.h, come specificato in ISO/IEC 9899: 1990 Linguaggi di programmazione C (clausola 7) o ISO/IEC: 1990 Linguaggi di programmazione-C EMENDAMENTO 1: Integrità C, (clausola 7), come ap proprio, come se per inclusione. Nella Libreria standard C++, , tuttavia, le dichiarazioni e le definizioni (ad eccezione dei nomi che sono definiti come macro in C) rientrano nell'ambito dello spazio dei nomi (3.3.5) dello std dello spazio dei nomi .

Quindi lo standard, modo non deprecato, canonica da usare (per esempio) printf in C++ è quello di #include <cstdio> e quindi richiamare std::printf.

1

No, è necessario utilizzare le intestazioni ++ wrapper di C (per esempio come <cstdio>). Quelli si prendono cura di tutto questo per te.

Se è un'intestazione che non dispone di quelle, allora sì, vorrai racchiuderle in extern "C" {}.

ETA: Vale la pena notare che molte implementazioni includeranno il wrapper all'interno del file .h come di seguito, in modo da poter fare a meno di non farlo da soli.

#ifdef __cplusplus 
extern "C" { 
#endif 

#ifdef __cplusplus 
} 
#endif 
+0

Vale la pena notare che le intestazioni '' ecc. tecnicamente inseriscono le loro definizioni nello spazio dei nomi 'std'. (Molte implementazioni li mettono anche nello spazio dei nomi di primo livello, ma non è quello che dice lo standard.) – Nemo

-1

E è una buona idea per far conoscere al compilatore in modo che possa aspettarsi codice C durante la compilazione di C++. Potresti anche scoprire che i file di intestazione contengono essi stessi extern "C" { come guardie.

Per esempio, curses.h sul mio sistema contiene:

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

* "fa sapere al compilatore che può aspettarsi codice C durante la compilazione come C++" * - Questo non è ciò che "extern" C "" fa. Non cambia l'interpretazione del codice. Non si applica nemmeno al codice. È una direttiva di collegamento linguistico che ordina al compilatore di generare simboli compatibili con quelli che il linker si aspetta per C. Rende il codice C++ richiamabile da C, ma non modifica la generazione del codice. – IInspectable

+0

@IInspectable Does not _ "indica al compilatore di generare simboli compatibili con quelli che il linker si aspetta per C" _ implica che si applica al codice o almeno alla convenzione di chiamata del codice? Sta sicuramente permettendo al compilatore (così come al linker) di sapere qualcosa. – Tanz87

+0

@ Tanz87: Non modifica la generazione del codice di un bit. Il codice oggetto generato è identico ao senza "extern" C "'. La direttiva si applica solo alla denominazione dei simboli. Non ha alcun rapporto con le convenzioni di chiamata. – IInspectable

1

Sì, si fa. Tuttavia, molti sistemi (in particolare Linux) stanno già aggiungendo un bracketing extern "C" come fai tu. Vedere i file (su Linux) /usr/include/unistd.h/usr/include/features.h e la macro __BEGIN_DECLS definita in /usr/include/sys/cdefs.h e utilizzata in molti file di sistema Linux.

Quindi su Linux, di solito è possibile evitare il proprio extern "C" ma non danneggia (e, IMHO, migliorare la leggibilità in quel caso).

11

Le intestazioni di sistema C in genere includono già un blocco extern "C", protetto da #ifdef __cplusplus. In questo modo le funzioni vengono automaticamente dichiarate come extern "C" quando compilate come C++ e non è necessario farlo manualmente.

Per esempio sul mio sistema unistd.h e fcntl.h inizio con __BEGIN_DECLS e terminano con __END_DECLS, quali sono le macro definite in 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

A mio parere è il dovere del file di intestazione esportazione di utilizzare extern "C " appropriatamente.

0

Ho appena controllato due volte lo stdlib.h per il compilatore GNU e le dichiarazioni non usano "C" extern come dichiarazioni.

edit:

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

Così tra cui le vecchie intestazioni saranno posizionare dichiarazioni sulla std fornito _GLIBCPP_USE_NAMESPACES è definito?