¿Cómo llamar a la función C ++ desde C?

Yo se esto.

Llamando a la función C desde C ++:

Si mi aplicación estaba en C ++ y tuve que llamar a funciones de una biblioteca escrita en C. Entonces habría usado

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

Esto no C_library_function el nombre C_library_function y el enlazador encontraría el mismo nombre en sus archivos de entrada * .lib y el problema está resuelto.

Llamando a la función C ++ desde C ???

Pero aquí estoy ampliando una gran aplicación que está escrita en C y necesito usar una biblioteca escrita en C ++. El cambio de nombre de C ++ está causando problemas aquí. Linker se queja de los símbolos no resueltos. Bueno, no puedo usar el comstackdor C ++ sobre mi proyecto C porque eso está rompiendo muchas otras cosas. ¿Dónde está la salida?

Por cierto, estoy usando MSVC

Necesita crear una API C para exponer la funcionalidad de su código C ++. Básicamente, tendrá que escribir el código de C ++ que se declara extern “C” y que tiene una API pura de C (que no usa clases, por ejemplo) que envuelve la biblioteca de C ++. Luego, usa la biblioteca de C wrapper pura que ha creado.

Su API de C puede seguir opcionalmente un estilo orientado a objetos, aunque C no esté orientado a objetos. 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); } 

Lo haría de la siguiente manera:

(Si trabaja con MSVC, ignore los comandos de comstackción de GCC)

Supongamos que tengo una clase C ++ llamada AAA , definida en los archivos aaa.h, aaa.cpp , y que la clase AAA tiene un método llamado sayHi (const char * name) , que quiero habilitar para el código C.

El código C ++ de la clase AAA – Pure C ++, no lo modifico:

// 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; } 

Comstackndo esta clase como se hace regularmente para C ++. Este código "no sabe" que va a ser utilizado por el código C. Usando el comando:

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

Ahora, también en C ++, creando un conector C. Definirlo en archivos aaa_c_connector.h, aaa_c_connector.cpp . Este conector va a definir una función C, llamada AAA_sayHi (cosnt char * name) , que usará una instancia de AAA y llamará a su método:

// aaa_c_connector.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 

Comstackndo, de nuevo, usando un comando de comstackción C ++ regular:

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

Ahora tengo una biblioteca compartida (libaaa_c_connector.so), que implementa la función C AAA_sayHi (const char * name) . Ahora puedo crear un archivo principal C y comstackrlo todo junto:

// C Principal

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

Comstackndo usando un comando de comstackción C:

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

Necesitaré establecer LD_LIBRARY_PATH para que contenga $ PWD, y si ejecuto el ejecutable ./c_aaa , obtendré el resultado que espero:

 Hi David Hi James 

EDITAR:

En algunas distribuciones de Linux, -laaa y -lstdc++ también pueden ser necesarios para el último comando de comstackción. Gracias a @AlaaM. para la atención

Suponiendo que la API de C ++ es compatible con C (sin clases, plantillas, etc.), puede envolverla en la extern "C" { ... } , tal como lo hizo al ir hacia el otro lado.

Si quieres exponer objetos y otras cosas bonitas de C ++, tendrás que escribir una API de envoltura.

Tendrá que escribir un contenedor para C en C ++ si desea hacerlo. C ++ es compatible con versiones anteriores, pero C no es compatible con versiones anteriores.

Exporte sus funciones de C ++ como extern “C” (también conocido como símbolos de estilo C), o use el formato de archivo .def para definir símbolos de exportación no decorados para el enlazador C ++ cuando crea la biblioteca C ++, entonces el enlazador C no debería tener problemas al leerlo

 #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; }