Domanda

Sto lavorando su un progetto che ha un sacco di patrimonio C del codice. Abbiamo iniziato a scrivere in C ++, con l'intento di fine convertire il codice legacy, pure. Sono un po 'confuso su come il C e interagiscono C ++. Capisco che avvolgendo il C codice con extern "C" il compilatore C ++ non storpiare il C i nomi di codice, ma non sono del tutto sicuro di come implementare questa.

Quindi, nella parte superiore di ogni C file di intestazione (dopo l'inclusione guardie), abbiamo

#ifdef __cplusplus
extern "C" {
#endif

e in fondo, scriviamo

#ifdef __cplusplus
}
#endif

Tra i due, abbiamo tutti i nostri prototipi comprende, typedef, e la funzione. Ho un paio di domande, per vedere se sto capire questo correttamente:

  1. Se ho un C file

    ++ A.hh che include un C file di intestazione B.h, include un altro C file di intestazione C.h, come funziona? penso che quando il compilatore passi in B.h, sarà definito __cplusplus, quindi vi avvolgerà il codice con extern "C" (E __cplusplus non sarà definita all'interno di questo blocco). Così, quando passi in C.h, __cplusplus non sarà definita e il codice non sarà avvolto in extern "C". È corretto?

  2. C'è sbagliato nulla con avvolgendo un pezzo di codice con extern "C" { extern "C" { .. } }? Quale sarà la seconda extern "C" fare?

  3. Noi non mettere questa wrapper per i file .c, solo i file .h. Allora, che cosa succede se una funzione non ha un prototipo? Fa il compilatore pensa che si tratta di una funzione C ++?

  4. Stiamo anche utilizzando alcuni di terze parti codice che è scritto in C , e lo fa non hanno questo tipo di wrapper esso. Ogni volta che includono un colpo di testa da quella biblioteca, Ho messo un extern "C" intorno al # include. È questo il modo giusto per affrontare che?

  5. Infine, è questo set up una buona idea? C'è qualcos'altro che dovremmo fare? Stiamo per essere miscelazione C e C ++ per il prossimo futuro, e io vuole assicurarsi che stiamo coprendo tutto le nostre basi.

È stato utile?

Soluzione

extern "C" non cambia il modo in cui il compilatore legge il codice. Se il codice è in un file .c, verrà compilato come C, se si trova in un file cpp, verrà compilato come C ++ (a meno che non si fa qualcosa di strano alla configurazione).

Quello che fa è extern "C" influisce linkage. funzioni C ++, quando compilato, hanno i loro nomi storpiato - questo è ciò che rende il sovraccarico possibile. Il nome della funzione viene modificato in base ai tipi e numero di parametri, in modo che due funzioni con lo stesso nome avranno nomi diversi simboli.

Codice all'interno di un extern "C" è ancora il codice C ++. Ci sono limitazioni su cosa si può fare in un blocco extern "C", ma sono tutta una questione di linkage. Non è possibile definire tutti i nuovi simboli che non possono essere costruiti con collegamento C. Ciò significa che non classi o modelli, per esempio.

blocchi extern "C" nido bene. C'è anche extern "C++" se vi trovate irrimediabilmente intrappolato all'interno delle regioni extern "C", ma non è una buona idea dal punto di vista pulizia.

Ora, in particolare per quanto riguarda le vostre domande numerate:

Per quanto riguarda # 1: __cplusplus rimarrà all'interno definito di blocchi extern "C". Questo non importa, però, dato che i blocchi dovrebbero nido ordinatamente.

Per quanto riguarda # 2: sarà definito __cplusplus per qualsiasi unità di compilazione che viene eseguito attraverso il compilatore C ++. In generale, la disponibilità di mezzi cpp file e tutti i file che vengono inclusi da quel file cpp. Lo stesso .h (o .hh o .hpp o che cosa-sono-te) potrebbe essere interpretata come C o C ++ in tempi diversi, se diverse unità di compilazione li includono. Se si desidera che i prototipi nel file h per indicare i nomi dei simboli C, quindi devono avere extern "C" quando viene interpretato come C ++, e non dovrebbero avere extern "C" quando viene interpretato come C -. Da qui il controllo #ifdef __cplusplus

Per rispondere alla tua domanda # 3: funzioni senza prototipi avrà legame C ++ se sono nei file cpp e non all'interno di un blocco extern "C". Questo va bene, però, perché se non ha un prototipo, può essere chiamato solo da altre funzioni nello stesso file, e quindi non si cura di ciò che in genere gli sguardi di collegamento piace, perché non si ha intenzione di avere quella funzione essere chiamato da qualsiasi cosa al di fuori della stessa unità di compilazione in ogni caso.

Per 4 #, hai esattamente. Se siete tra cui un colpo di testa per il codice che ha collegamento C (come il codice che è stato compilato da un compilatore C), allora è necessario extern "C" l'intestazione - in questo modo si sarà in grado di collegare con la libreria. (In caso contrario, il vostro linker sarebbe in cerca di funzioni con nomi come _Z1hic quando si stavano cercando void h(int, char)

5:. Questo tipo di miscelazione è un motivo comune per l'uso extern "C", e non vedo nulla di sbagliato nel fare in questo modo - solo assicuratevi di capire cosa si sta facendo

Altri suggerimenti

  1. extern "C" non cambia la presenza o l'assenza della macro __cplusplus. Si cambia solo il collegamento e il nome-pressare delle dichiarazioni avvolti.

  2. È possibile blocchi extern "C" nido tranquillamente.

  3. Se si compila il file .c come C ++, allora tutto quanto non in un blocco extern "C", e senza un prototipo di extern "C" sarà trattata come una funzione C ++. Se li si compila come C poi, naturalmente, tutto sarà una funzione C.

  4. Si

  5. Si può tranquillamente mescolare C e C ++ in questo modo.

Un paio di grattacapi che sono colloraries a risposta eccellente di Andrew Shelansky e non essere d'accordo un po 'con non cambia il modo in cui il compilatore legge il codice

Perché i vostri prototipi di funzione sono compilati come C, non si può avere un sovraccarico degli stessi nomi di funzione con parametri diversi - che è una delle caratteristiche fondamentali del nome mangling del compilatore. E 'descritto come una questione del collegamento, ma che non è del tutto vero -. Otterrete gli errori sia dal compilatore e il linker

Gli errori del compilatore sarà se si tenta di utilizzare C ++ dispone di dichiarazione di prototipo, come sovraccarico.

Gli errori di linker si verificherà più tardi perché apparirà la funzione di non essere trovato, se si fa non hanno extern "C" wrapper per le dichiarazioni e l'intestazione è inclusi in una miscela di C e C ++ fonte.

Una ragione per scoraggiare le persone di utilizzare il di compilazione C come C ++ impostazione è perché questo significa che il loro codice sorgente non è più portatile. Tale impostazione è un'impostazione progetto e quindi se un file .c è caduto in un altro progetto, non sarà compilato come C ++. Avrei preferito la gente prendere il tempo per rinominare i suffissi di file da cpp.

Si tratta del ABI, al fine di lasciare entrambe le interfacce C e C ++ usare l'applicazione C senza alcun problema.

Dato che il linguaggio C è molto facile, la generazione di codice è stato stabile per molti anni per diversi compilatori, come GCC, Borland C \ C ++, MSVC etc.

Mentre C ++ diventa sempre più popolare, un sacco di cose devono essere aggiunti nel nuovo dominio C ++ (per esempio, infine, la Cfront fu abbandonato a AT & T perché C non poteva coprire tutte le caratteristiche di cui ha bisogno). Come ad esempio modello la generazione del codice funzione, e la compilazione in tempo, dal passato, il diverso compilatore fornitori in realtà ha fatto l'effettiva attuazione del compilatore e linker C ++ separatamente, i ABI reali non sono compatibili a tutti per il C ++ programma a diverse piattaforme.

La gente potrebbe ancora come per l'attuazione del programma vero e proprio in C ++, ma ancora mantenere la vecchia interfaccia C e ABI, come al solito, il file di intestazione deve dichiarare extern "C" {} , dice al compilatore generare compatibile / vecchio / semplice / facile C ABI per le funzioni di interfaccia se il compilatore è compilatore C non C ++.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top