Yo se esto.
Llamar a la función C desde C ++:
Si mi aplicación estuviera en C ++ y tuviera que llamar a funciones desde 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 alteraría el nombre C_library_function
y el enlazador encontraría el mismo nombre en sus archivos de entrada * .lib y el problema se resolvería.
Llamando a la función C ++ desde C ???
Pero aquí estoy extendiendo una gran aplicación que está escrita en C y necesito usar una biblioteca que está escrita en C ++. La alteración de nombres de C ++ está causando problemas aquí. Linker se queja de los símbolos no resueltos. Bueno, no puedo usar el compilador C ++ sobre mi proyecto C porque eso está rompiendo muchas otras cosas. ¿Dónde está la salida?
Por cierto, estoy usando MSVC
fuente
Respuestas:
Necesita crear una API C para exponer la funcionalidad de su código C ++. Básicamente, necesitará escribir código C ++ que se declare extern "C" y que tenga una API C pura (sin usar clases, por ejemplo) que envuelva la biblioteca C ++. Luego, usa la biblioteca contenedora de C pura que ha creado.
Su API 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<MyType*>(untyped_ptr); delete typed_ptr; } void mylibrary_mytype_doit(mylibrary_mytype_t untyped_self, int param) { MyType* typed_self = static_cast<MyType*>(untyped_self); typed_self->doIt(param); }
fuente
*.cpp file
, también necesitaba ajustar las funciones en#ifdef _cplusplus
+extern "C"
para evitar errores de "referencia indefinida a" en el momento del enlace.Lo haría de la siguiente manera:
(Si trabaja con MSVC, ignore los comandos de compilació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 <iostream> #include "aaa.h" AAA::AAA() { } void AAA::sayHi(const char *name) { std::cout << "Hi " << name << std::endl; }
Compilar esta clase como se hace habitualmente 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. Definiéndolo 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 <cstdlib> #include "aaa_c_connector.h" #include "aaa.h" #ifdef __cplusplus extern "C" { #endif // Inside this "extern C" block, I can implement functions in C++, which will externally // appear as C functions (which means that the function IDs will be their names, unlike // the regular C++ behavior, which allows defining multiple functions with the same name // (overloading) and hence uses function signature hashing to enforce unique IDs), 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
Compilarlo, nuevamente, usando un comando de compilación normal de C ++:
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 en C y compilarlo todo junto:
main.c
#include "aaa_c_connector.h" int main() { AAA_sayHi("David"); AAA_sayHi("James"); return 0; }
Compilarlo usando un comando de compilación de C:
gcc main.c -L. -laaa_c_connector -o c_aaa
Necesitaré configurar LD_LIBRARY_PATH para que contenga $ PWD, y si ejecuto el ejecutable ./c_aaa , obtendré el resultado que espero:
EDITAR:
En algunas distribuciones de Linux,
-laaa
y-lstdc++
también puede ser necesario para el último comando de compilación. Gracias a @AlaaM. para la atenciónfuente
gcc usecpp.c -L. -laaa_c_connector -Wl,-rpath,. -o c_aaa
usecpp.c
?gcc main.c -L. -laaa_c_connector -laaa -lstdc++ -o c_aaa
. Tenga en cuenta el-laaa
y-lstdc+++
main.c
ausecpp.c
. Lo acabo de revertir ... Sobre el otro comentario, debería funcionar también como está. La segunda compilación usa-laaa
y probablemente debería ser suficiente (la escribí hace más de 1,5 años, no recuerdo muy bien lo que hice, pero creo que probé cada línea antes de publicar)Tendrá que escribir un contenedor para C en C ++ si desea hacer esto. C ++ es compatible con versiones anteriores, pero C no es compatible con versiones anteriores.
fuente
Suponiendo que la API de C ++ es compatible con C (sin clases, plantillas, etc.), puede ajustarla
extern "C" { ... }
, tal como lo hizo cuando iba en sentido contrario.Si desea exponer objetos y otras cosas interesantes de C ++, tendrá que escribir una API contenedora.
fuente
exporta tus funciones de C ++ como "C" externo (también conocido como símbolos de estilo C), o usa 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 para leerlo
fuente
#include <iostream> ////////////// // 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<A *>(thisPtr); classPtr->dump (); } } static void *deleteA (void *thisPtr) { // destroy the A class if (thisPtr != NULL) { delete (static_cast<A *>(thisPtr)); } } } //////////////////////////////////// // this can be compiled as C code // //////////////////////////////////// int main (int argc, char **argv) { void *handle = createA(); dumpA (handle); deleteA (handle); return 0; }
fuente
Puede prefijar la declaración de función con la palabra clave externa "C", por ejemplo
extern "C" int Mycppfunction ()
{
// El código va aquí
return 0;
}
Para obtener más ejemplos, puede buscar más en Google sobre la palabra clave "externa". Necesita hacer algunas cosas más, pero no es difícil que obtenga muchos ejemplos de Google.
fuente