Ho bisogno di un blocco “C” esterno per includere intestazioni C standard?

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 ++.

Per esempio:

 extern "C" { #include  #include  } 

Il comportamento di e 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 , e degli altri header 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”.

Il modulo C ++ canonico di quelle intestazioni è , , ecc. E sono specificate dalla sezione 17.4.1.2 (3) dello standard C ++, che dice:

                

Ad eccezione di quanto indicato nelle clausole da 18 a 27, il contenuto di ogni intestazione cname deve essere uguale a quello dell’intestazione corrispondente nome.h, come specificato in ISO / IEC 9899: 1990 Linguaggi di programmazione C (clausola 7) o ISO / IEC : 1990 Programming Languages-C EMENDAMENTO 1: C Integrità, (Clausola 7), come appropriato, come se per inclusione. Nella libreria standard C ++, tuttavia, le dichiarazioni e le definizioni (ad eccezione dei nomi definiti come macro in C) rientrano nell’ambito dello spazio dei nomi (3.3.5) dello spazio dei nomi std.

Quindi il modo standard, non deprecato, canonico di usare (es.) printf in C ++ è #include e quindi invocare std::printf .

Le intestazioni di sistema C di solito 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.

Ad esempio sul mio sistema unistd.h e fcntl.h iniziano con __BEGIN_DECLS e terminano con __END_DECLS , che 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 

Si. Tuttavia, molti sistemi (in particolare Linux) stanno già aggiungendo un bracketing extern "C" externale come fai tu. Vedi (su Linux) i file /usr/include/unistd.h /usr/include/features.h e la macro __BEGIN_DECLS definita in /usr/include/sys/cdefs.h e usata in molti file di sistema Linux inclusi.

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

No, dovresti usare le intestazioni del wrapper C ++ (ad esempio ). Quelli si prendono cura di tutto questo per te.

Se è un’intestazione che non ha quelle, allora sì, vorrai avvolgerle nella extern "C" {} .

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

 #ifdef __cplusplus extern "C" { #endif #ifdef __cplusplus } #endif 

È una buona idea lasciare che il compilatore lo sappia in modo che possa aspettarsi il codice C durante la compilazione come C ++. Potresti anche scoprire che i file header stessi contengono extern "C" { come guardie.

Ad esempio, curses.h sul mio sistema contiene:

 #ifdef __cplusplus extern "C" { ... 

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

modificare:

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

Quindi includendo le vecchie intestazioni verranno posizionate le dichiarazioni su std fornito _GLIBCPP_USE_NAMESPACES è definito?