Pregunta

Sé que esto.

llamando a la función C de C ++:

Si mi solicitud fue en C ++ y tuve que llamar a las funciones de una biblioteca escrita en C. Entonces habría utilizado

//main.cpp

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

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

Llamando C función ++ de C ???

Pero aquí les extiendo una gran aplicación que está escrito en C y necesito usar una biblioteca que está escrito en C ++. Nombre mangling de C ++ está causando problemas aquí. Enlazador se queja de los símbolos sin resolver. Bueno, no puedo utilizar el compilador C ++ C por encima de mi proyecto, porque eso es romper muchas otras cosas. ¿Cuál es la salida?

Por cierto estoy usando MSVC

¿Fue útil?

Solución

Se necesita crear una API C para exponer la funcionalidad de su código C ++. Básicamente, usted tendrá que escribir el código C ++ que se declaró extern "C", y que tiene una API C pura (sin el uso de clases, por ejemplo) que envuelve a la biblioteca de C ++. A continuación, se utiliza la biblioteca de C envoltorio pura que ha creado.

Su C API puede seguir opcionalmente un estilo orientado a objetos, a pesar de que C no es orientado a objetos. Ej:

 // *.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);
 }

Otros consejos

Yo lo haría de la siguiente manera:

(Si se trabaja con MSVC, ignorar las órdenes de compilación de GCC)

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

El código C ++ de la clase AAA - Pure C ++, no modificarlo:

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

La compilación de esta clase como se hace regularmente para C ++. Este código de "no sabe" que va a ser utilizado por el código C. Uso del mando:

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

Ahora, también en C ++, la creación de un conector C. Definiéndola en los archivos aaa_c_connector.h, aaa_c_connector.cpp . Este conector se va a definir una función C, llamado AAA_sayHi (cosnt char * nombre) , que va a utilizar una instancia de AAA y será 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

La compilación que, de nuevo, usando un C ++ regular de comando de compilación:

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 * nombre) . Ahora puedo crear un archivo principal C y compilar todo junto:

main.c

#include "aaa_c_connector.h"

int main() {
    AAA_sayHi("David");
    AAA_sayHi("James");

    return 0;
}

Compilarlo mediante un comando de compilación C:

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

Me tendrá que establecer LD_LIBRARY_PATH para contener $ PWD, y si corro el ejecutable ./ c_aaa , voy a obtener el resultado que espero:

Hi David
Hi James

EDIT:

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

Suponiendo que el C ++ API es compatible con C (no hay clases, plantillas, etc.), se puede envolver en extern "C" { ... }, tal como lo hizo cuando se va por otro camino.

Si desea exponer objetos y otras cosas linda C ++, tendrá que escribir una API envoltorio.

tendrá que escribir un contenedor para C en C ++ si usted quiere hacer esto. C ++ es compatible hacia atrás, pero C no es compatible hacia delante.

exportar sus funciones de C ++ como extern "C" (también conocido como símbolos de estilo C), o utilice el formato de archivo .def para definir símbolos de exportación sin decoración para el C ++ enlazador cuando se crea la biblioteca de C ++, a continuación, el enlazador C no debería tener problemas leerlo

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

Puede prefijar la declaración de la función con la palabra clave extern “C”, por ejemplo.

extern “C” int Mycppfunction ()

{

// Código va aquí

return 0;

}

Para más ejemplos se puede buscar más en Google sobre la palabra clave “externo”. Que tiene que hacer algunas cosas más, pero no es difícil que obtendrá un montón de ejemplos de Google.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top