Utilizzo della libreria C ++ nel codice C.


102

Ho una libreria C ++ che fornisce varie classi per la gestione dei dati. Ho il codice sorgente per la libreria.

Voglio estendere l'API C ++ per supportare le chiamate di funzione C in modo che la libreria possa essere utilizzata con codice C e codice C ++ allo stesso tempo.

Sto usando la catena di strumenti GNU (gcc, glibc, ecc.), Quindi il supporto del linguaggio e dell'architettura non sono un problema.

Ci sono ragioni per cui questo non è tecnicamente possibile?

Ci sono trucchi a cui devo fare attenzione?

Sono disponibili risorse, codice di esempio e / o documentazione in merito?


Alcune altre cose che ho scoperto:

  1. Usa quanto segue per racchiudere le intestazioni C ++ che devono essere utilizzate dal codice C.

#ifdef __cplusplus
extern "C" {  
#endif  
//  
// Code goes here ...  
//  
#ifdef __cplusplus  
} // extern "C"  
#endif
  1. Mantieni le interfacce C ++ "reali" in file di intestazione separati che non sono inclusi dal principio C. Pensa qui al principio PIMPL . Usare le #ifndef __cplusplus #errorcose qui aiuta a rilevare qualsiasi follia.
  2. Attento agli identificatori C ++ come nomi nel codice C.
  3. Enumerazioni di dimensioni variabili tra i compilatori C e C ++. Probabilmente non è un problema se stai usando la catena di strumenti GNU, ma fai comunque attenzione.
  4. Per gli struct seguire la seguente forma in modo che C non venga confuso.

    typedef struct X { ... } X
  5. Quindi usa i puntatori per passare gli oggetti C ++, devono solo essere dichiarati in C come struct X dove X è l'oggetto C ++.

Tutto questo è per gentile concessione di un amico che è un mago in C ++.


5
Un po 'tardi, ma ho scritto un piccolo howto sul wrapper C per C ++: teddy.ch/c++_library_in_c
Teddy

Risposte:


69

Sì, questo è certamente possibile. Dovrai scrivere un livello di interfaccia in C ++ che dichiari le funzioni con extern "C":

extern "C" int foo(char *bar)
{
    return realFoo(std::string(bar));
}

Quindi, chiamerai foo()dal tuo modulo C, che passerà la chiamata alla realFoo()funzione che è implementata in C ++.

Se è necessario esporre una classe C ++ completa con membri di dati e metodi, potrebbe essere necessario eseguire più lavoro di questo semplice esempio di funzione.


Dovrebbe extern "C"essere inserito solo nelle dichiarazioni (e non nelle definizioni)? Perché hai menzionato "il livello che dichiara le funzioni" ma il tuo codice di esempio è anche una definizione. In altre parole, dovremmo inserirlo nei file di intestazione o nei file di origine? (O entrambi?)
kyriakosSt

@ KyrSt: Se hai un file di intestazione con una dichiarazione di funzione, devi almeno metterlo extern "C"lì. Il tuo compilatore ti dirà se devi metterlo anche nella definizione.
Greg Hewgill

23

C ++ FAQ Lite: "Come combinare codice C e C ++" .

Alcuni trucchi sono descritti nelle risposte a queste domande:

  • [32.8] Come posso passare un oggetto di una classe C ++ a / da una funzione C?
  • [32.9] La mia funzione C può accedere direttamente ai dati in un oggetto di una classe C ++?

12

Trucco principale: le eccezioni non possono essere catturate in C. Se c'è la possibilità che un'eccezione sorga nel codice C ++, scrivi il tuo codice C oi tuoi wrapper C ++ con molta attenzione. Al contrario, meccanismi simili a eccezioni (cioè, longjump) nel codice C (come si trovano in vari linguaggi di scripting) non sono necessari per invocare distruttori per oggetti C ++ nello stack.


2
Ottimo punto sulle chiamate in longjump. Anche se non li uso direttamente, i framework di test che utilizzo li implementano. Qualcosa da tenere a mente. Grazie
Misha M

3

puoi mescolare codice C / C ++. Se la tua funzione main () è in C ++, devi solo assicurarti che le tue funzioni c siano dichiarate

extern "C"

Se il tuo main è C, allora probabilmente stai bene tranne che per le variabili statiche. Qualsiasi costruttore con le tue variabili statiche dovrebbe essere chiamato prima dell'inizio di main (). Questo non accadrà se C è il tuo principale. Se hai molte variabili statiche, la cosa migliore da fare è sostituire le variabili statiche con singleton.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.