Wie C ++ function von C aufrufen?

Ich weiß das.

C-function von C ++ aufrufen:

Wenn meine Anwendung in C ++ war und ich functionen aus einer in C geschriebenen Bibliothek aufrufen musste, hätte ich sie benutzt

//main.cpp extern "C" void C_library_function(int x, int y);//prototype C_library_function(2,4);// directly using it. 

Dies würde den Namen C_library_function nicht C_library_function und der Linker würde in seinen * .lib-Eingabedateien denselben Namen finden, und das Problem ist getriggers.

Aufruf der C ++ function von C ???

Aber hier erweitere ich eine große Anwendung, die in C geschrieben ist und ich brauche eine Bibliothek, die in C ++ geschrieben ist. Der Name Mangling von C ++ verursacht hier Probleme. Linker beschwert sich über die ungetriggersen Symbole. Nun, ich kann den C ++ – Compiler nicht über mein C-Projekt benutzen, weil das viele andere Dinge kaputt macht. Was ist der Ausweg?

Übrigens benutze ich MSVC

Sie müssen eine C-API erstellen, um die functionalität Ihres C ++ – Codes verfügbar zu machen. Im Grunde müssen Sie C ++ – Code schreiben, der extern “C” deklariert ist und der eine reine C-API hat (die beispielsweise keine classn verwendet), die die C ++ – Bibliothek umschließt. Dann verwenden Sie die reine C-Wrapper-Bibliothek, die Sie erstellt haben.

Ihre C-API kann optional einem objektorientierten Stil folgen, obwohl C nicht objektorientiert ist. Ex:

  // *.h file // ... #ifdef __cplusplus #define EXTERNC extern "C" #else #define EXTERNC #endif typedef void* mylibrary_mytype_t; EXTERNC mylibrary_mytype_t mylibrary_mytype_init(); EXTERNC void mylibrary_mytype_destroy(mylibrary_mytype_t mytype); EXTERNC void mylibrary_mytype_doit(mylibrary_mytype_t self, int param); #undef EXTERNC // ... // *.cpp file mylibrary_mytype_t mylibrary_mytype_init() { return new MyType; } void mylibrary_mytype_destroy(mylibrary_mytype_t untyped_ptr) { MyType* typed_ptr = static_cast(untyped_ptr); delete typed_ptr; } void mylibrary_mytype_doit(mylibrary_mytype_t untyped_self, int param) { MyType* typed_self = static_cast(untyped_self); typed_self->doIt(param); } 

Ich würde es auf folgende Weise tun:

(Wenn Sie mit MSVC arbeiten, ignorieren Sie die GCC-Kompilierungsbefehle)

Angenommen, ich habe eine C ++ – class namens AAA , definiert in den Dateien aaa.h, aaa.cpp , und die class AAA hat eine Methode namens sayHi (const char * name) , die ich für C-Code aktivieren möchte.

Der C ++ Code der class AAA – Pure C ++, ich modifiziere ihn nicht:

// aaa.h

 #ifndef AAA_H #define AAA_H class AAA { public: AAA(); void sayHi(const char *name); }; #endif 

// aaa.cpp

 #include  #include "aaa.h" AAA::AAA() { } void AAA::sayHi(const char *name) { std::cout < < "Hi " << name << std::endl; } 

Kompilieren dieser class wie für C ++ regelmäßig durchgeführt. Dieser Code "weiß nicht", dass er von C-Code verwendet wird. Verwenden des Befehls:

 g++ -fpic -shared aaa.cpp -o libaaa.so 

Erstellen Sie jetzt auch in C ++ einen C-Connector. Definieren Sie es in Dateien aaa_c_connector.h, aaa_c_connector.cpp . Dieser Connector definiert eine C-function namens AAA_sayHi (cosn char * name) , die eine Instanz von AAA verwendet und ihre Methode aufruft :

// aaa_c_verbinder.h

 #ifndef AAA_C_CONNECTOR_H #define AAA_C_CONNECTOR_H #ifdef __cplusplus extern "C" { #endif void AAA_sayHi(const char *name); #ifdef __cplusplus } #endif #endif 

// aaa_c_connector.cpp

 #include  #include "aaa_c_connector.h" #include "aaa.h" #ifdef __cplusplus extern "C" { #endif // Inside this "extern C" block, I can define C functions that are able to call C++ code static AAA *AAA_instance = NULL; void lazyAAA() { if (AAA_instance == NULL) { AAA_instance = new AAA(); } } void AAA_sayHi(const char *name) { lazyAAA(); AAA_instance->sayHi(name); } #ifdef __cplusplus } #endif 

Kompilieren Sie es erneut mit einem regulären C ++ - Kompilierbefehl:

 g++ -fpic -shared aaa_c_connector.cpp -L. -laaa -o libaaa_c_connector.so 

Jetzt habe ich eine gemeinsame Bibliothek (libaaa_c_connector.so), die die C-function AAA_sayHi (const char * name) implementiert. Ich kann jetzt eine C-Hauptdatei erstellen und alles zusammen kompilieren:

// Haupt c

 #include "aaa_c_connector.h" int main() { AAA_sayHi("David"); AAA_sayHi("James"); return 0; } 

Kompilieren mit einem C-Kompilierbefehl:

 gcc main.c -L. -laaa_c_connector -o c_aaa 

Ich muss LD_LIBRARY_PATH setzen, um $ PWD zu enthalten, und wenn ich die ausführbare Datei ./c_aaa ausführe , bekomme ich die erwartete Ausgabe:

 Hi David Hi James 

BEARBEITEN:

Bei einigen Linux-Distributionen können -laaa und -lstdc++ auch für den letzten Kompilierungsbefehl erforderlich sein. Danke an @AlaaM. für die Aufmerksamkeit

Angenommen, die C ++ – API ist C-kompatibel (keine classn, Vorlagen usw.), können Sie sie in extern "C" { ... } , so wie Sie es auch gemacht haben, wenn Sie in die andere Richtung gegangen sind.

Wenn Sie Objekte und andere süße C ++ – Objekte verfügbar machen möchten, müssen Sie eine Wrapper-API schreiben.

Sie müssen einen Wrapper für C in C ++ schreiben, wenn Sie dies tun wollen. C ++ ist abwärtskompatibel, aber C ist nicht vorwärtskompatibel.

Exportieren Sie Ihre C ++ – functionen als extern “C” (aka C-Stil-Symbole) oder verwenden Sie das .def-Dateiformat, um undekorierte Exportsymbole für den C ++ – Linker beim Erstellen der C ++ – Bibliothek zu definieren, dann sollte der C-Linker keine Probleme haben

 #include  ////////////// // C++ code // ////////////// struct A { int i; int j; A() {i=1; j=2; std::cout < < "class A created\n";} void dump() {std::cout << "class A dumped: " << i << ":" << j << std::endl;} ~A() {std::cout << "class A destroyed\n";} }; extern "C" { // this is the C code interface to the class A static void *createA (void) { // create a handle to the A class return (void *)(new A); } static void dumpA (void *thisPtr) { // call A->dump () if (thisPtr != NULL) // I'm an anal retentive programmer { A *classPtr = static_cast(thisPtr); classPtr->dump (); } } static void *deleteA (void *thisPtr) { // destroy the A class if (thisPtr != NULL) { delete (static_cast(thisPtr)); } } } //////////////////////////////////// // this can be compiled as C code // //////////////////////////////////// int main (int argc, char **argv) { void *handle = createA(); dumpA (handle); deleteA (handle); return 0; }