from - ¿Cómo llamar a la función C++ desde C?
extern function c (6)
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 compilador C ++ sobre mi proyecto C porque eso está rompiendo muchas otras cosas. ¿Dónde está la salida?
Por cierto, estoy usando MSVC
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
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;
}
Compilando 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 <cstdlib>
#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
Compilando, de nuevo, usando un comando de compilació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 compilarlo todo junto:
// C Principal
#include "aaa_c_connector.h"
int main() {
AAA_sayHi("David");
AAA_sayHi("James");
return 0;
}
Compilando usando un comando de compilació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 compilación. Gracias a @AlaaM. para la atención
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<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);
}
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.
#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;
}