Verwenden der C ++ - Bibliothek in C-Code

102

Ich habe eine C ++ - Bibliothek, die verschiedene Klassen zum Verwalten von Daten bereitstellt. Ich habe den Quellcode für die Bibliothek.

Ich möchte die C ++ - API erweitern, um C-Funktionsaufrufe zu unterstützen, damit die Bibliothek gleichzeitig mit C-Code und C ++ - Code verwendet werden kann.

Ich verwende die GNU-Toolkette (gcc, glibc usw.), sodass die Unterstützung von Sprache und Architektur kein Problem darstellt.

Gibt es Gründe, warum dies technisch nicht möglich ist?

Gibt es irgendwelche Fallstricke, auf die ich achten muss?

Gibt es dazu Ressourcen, Beispielcode und / oder Dokumentation?


Einige andere Dinge, die ich herausgefunden habe:

  1. Verwenden Sie Folgendes, um Ihre C ++ - Header zu verpacken, die von C-Code verwendet werden müssen.

#ifdef __cplusplus
extern "C" {  
#endif  
//  
// Code goes here ...  
//  
#ifdef __cplusplus  
} // extern "C"  
#endif
  1. Bewahren Sie "echte" C ++ - Schnittstellen in separaten Header-Dateien auf, die nicht im C enthalten sind. Denken Sie hier an das PIMPL-Prinzip . Die Verwendung von #ifndef __cplusplus #errorDingen hilft hier, Verrücktheit zu erkennen.
  2. Vorsicht vor C ++ - Bezeichnern als Namen im C-Code
  3. Aufzählungen unterschiedlicher Größe zwischen C- und C ++ - Compilern. Wahrscheinlich kein Problem, wenn Sie die GNU-Toolkette verwenden, aber seien Sie trotzdem vorsichtig.
  4. Folgen Sie für Strukturen dem folgenden Formular, damit C nicht verwechselt wird.

    typedef struct X { ... } X
  5. Verwenden Sie dann Zeiger zum Übergeben von C ++ - Objekten. Sie müssen nur in C als Struktur X deklariert werden, wobei X das C ++ - Objekt ist.

All dies wurde freundlicherweise von einem Freund zur Verfügung gestellt, der ein Assistent bei C ++ ist.

Misha M.
quelle
5
Etwas spät, aber ich habe ein kleines Howto über C-Wrapper für C ++ geschrieben: teddy.ch/c++_library_in_c
Teddy

Antworten:

69

Ja, das ist sicherlich möglich. Sie müssen eine Schnittstellenschicht in C ++ schreiben, die Funktionen deklariert mit extern "C":

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

Anschließend rufen Sie foo()von Ihrem C-Modul aus auf, das den Aufruf an die realFoo()in C ++ implementierte Funktion weiterleitet.

Wenn Sie eine vollständige C ++ - Klasse mit Datenelementen und Methoden verfügbar machen müssen, müssen Sie möglicherweise mehr Arbeit leisten als in diesem einfachen Funktionsbeispiel.

Greg Hewgill
quelle
Sollte extern "C"nur in Erklärungen (und nicht in Definitionen) platziert werden? Weil Sie "die Ebene, die Funktionen deklariert" erwähnt haben, aber Ihr Beispielcode auch eine Definition ist. Mit anderen Worten, sollten wir es in Header-Dateien oder Quelldateien platzieren? (Oder beides?)
kyriakosSt
@KyrSt: Wenn Sie eine Header-Datei mit einer Funktionsdeklaration haben, müssen Sie diese mindestens extern "C"dort ablegen . Ihr Compiler wird Ihnen mitteilen, ob Sie es auch in die Definition aufnehmen müssen.
Greg Hewgill
23

C ++ FAQ Lite: "Mischen von C- und C ++ - Code" .

Einige Fallstricke werden in Antworten auf diese Fragen beschrieben:

  • [32.8] Wie kann ich ein Objekt einer C ++ - Klasse an eine C-Funktion übergeben?
  • [32.9] Kann meine C-Funktion direkt auf Daten in einem Objekt einer C ++ - Klasse zugreifen?
Alex B.
quelle
12

Hauptproblem: Ausnahmen können in C nicht abgefangen werden. Wenn die Möglichkeit besteht, dass im C ++ - Code eine Ausnahme auftritt, schreiben Sie entweder Ihren C-Code oder Ihre C ++ - Wrapper sehr sorgfältig. Umgekehrt sind ausnahmeähnliche Mechanismen (dh Longjump) im C-Code (wie in verschiedenen Skriptsprachen zu finden) nicht erforderlich, um Destruktoren für C ++ - Objekte auf dem Stapel aufzurufen.

ejgottl
quelle
2
Toller Punkt über Longjump-Anrufe. Obwohl ich sie nicht direkt verwende, implementieren sie die von mir verwendeten Test-Frameworks. Etwas zu beachten. Danke
Misha M
3

Sie können C / C ++ - Code mischen. Wenn Ihre main () -Funktion in C ++ ausgeführt wird, müssen Sie nur sicherstellen, dass Ihre c-Funktionen deklariert sind

extern "C"

Wenn Ihre Hauptleitung C ist, sind Sie wahrscheinlich in Ordnung, mit Ausnahme statischer Variablen. Alle Konstruktoren mit Ihren statischen Variablen sollten vor dem Start von main () aufgerufen werden. Dies wird nicht passieren, wenn C Ihr Haupt ist. Wenn Sie viele statische Variablen haben, ist es am besten, statische Variablen durch Singletons zu ersetzen.

David Nehme
quelle