programa funciones ejemplos ejecutar dev compilar compilador como cabecera archivos c++ c compilation shared-libraries

c++ - funciones - gcc compilador



¿Puedo usar la biblioteca compartida creada en C++ en un programa C? (3)

Su código C no puede usar el encabezado C ++ <string> . Debe asegurarse de que las funciones en la API C ++ a las que se debe llamar desde C se declaren extern "C" (como lo ha hecho), y use solo los tipos reconocidos por un compilador C (como lo ha hecho).

También necesita vincular con el compilador de C ++ si alguno de sus códigos está en C ++. De lo contrario, puede hacerlo si está preparado para gastar mucha energía obteniendo las opciones de cargador correctas, pero es mucho más simple usar el compilador de C ++:

gcc -c cmain.c g++ -fPIC -shared -o cppfile.so cppfile.cpp g++ -o cmain cmain.o cppfile.so

Por supuesto, necesitas:

  1. Agregue #include <stdio.h> en cmain.c .
  2. Use std::string S(filename); en cppfile.cpp .

Además, si el programa se invoca sin argumentos, obtienes:

$ ./cmain terminate called throwing an exceptionAbort trap: 6 $ ./cmain x3 0 $

Debe protegerse contra el uso indebido, incluso en programas de prueba.

Estoy creando programas usando C. Sin embargo, necesito usar muchas bibliotecas que tienen API solo para C ++. Entonces, ¿es posible que pueda crear un objeto compartido en C ++ y luego acceder a su funcionalidad usando C?

  1. Los únicos datos que estaría pasando y devolviendo serían los tipos de datos compatibles con C.
  2. Convertir o migrar a cpp no ​​es una opción aquí.

Si no es posible interconectar estos códigos, ¿cómo obtengo información del código C ++ al código C? Intenté llamar a las funciones de C ++ desde C, pero recibo errores durante la vinculación cuando incluyo <string> . Entonces, cuando llamo a C ++ desde C, ¿debería usar ese código que sea compatible con el compilador de C?

C ++ header cppfile.hpp

#ifndef CPPFILE_H #define CPPFILE_H #ifdef __cplusplus extern "C" { #endif extern int myfunction(const char *filename); #ifdef __cplusplus } #endif #endif

C ++ archivo cppfile.cpp

#include "cppfile.hpp" #include <string> int myfunction(const char *filename) { String S(filename); return 0; }

C archivo cmain.c

#include "cppfile.hpp" int main(int argc, char **argv) { int i = myfunction(argv[1]); printf("%d/n", i); return 0; }

Compilando:

gcc -c cmain.c g++ -fPIC -shared -o cppfile.so cppfile.cpp


Esto es completamente posible. Aquí es cómo, rápidamente: 1.) Usted tiene un header.h con una API de C que no incluye ningún Cplusiness.

#ifndef MIXEDCCPP_H #define MIXEDCCPP_H #ifdef __cplusplus extern "C" { #endif #include <stdint.h> // Any C-compatible headers will go here. // C API goes here. C Functions can''t contain any CPPiness. void myclass_setName( void *pClassObj, const char *pName, int nameLen ); #ifdef __cplusplus } #endif #ifdef __cplusplus // Stuff that is only compatible with CPP goes here // __cplusplus section won''t get processed while compiling C files. #include <vector> // CPP headers. class MyClass { // Classes etc. }; #endif // #ifdef __cplusplus #endif // MIXEDCCPP_H

Luego, en .cpp, simplemente crea algunas funciones C-API que incluso pueden incluir CPP directamente en ellas:

#include "mixedccpp.h" extern "C" { // C API goes here. C Functions can''t contain any CPPiness in their prototypes. void myclass_setName( void *pClassObj, const char *pName, int nameLen ) { // But CPP knowledge can go inside the function - no problem, since this is a CPP file. MyClass *pMyClass = static_cast<MyClass *>(pClassObj); pMyClass->setName( pName, nameLen ); } } // #extern "C" // CPP Stuff goes here... or vice-versa.

En su caso, realmente no necesita ningún código CPP declarado en su encabezado ya que está llamando a bibliotecas externas. Pero necesita crear funciones compatibles con C en su archivo CPP, que puede llamar a las bibliotecas CPP. Utilice extern "C" para aquellas funciones que necesitan ser llamadas desde archivos C, y luego use C-structs en lugar de clases y, si las clases son necesarias, use void * para señalarlas y luego devolverlas a su clase desde el C función cada vez que necesita acceder a ellos. Un archivo MAKE estándar debería ser capaz de compilar esto perfectamente, suponiendo que compila archivos .cpp como .cpp y entiende por "C" externo.


Desea algo más como esto (y aquí usaré un ejemplo un poco más significativo):

C / C ++ encabezado - animal.h

#ifndef ANIMAL_H #define ANIMAL_H #ifdef __cplusplus class Animal { public: Animal() : age(0), height(0) {} Animal(int age, float height) : age(age), height(height) {} virtual ~Animal() {} int getAge(); void setAge(int new_age); float getHeight(); void setHeight(float new_height); private: int age; float height; // in metres! }; #endif /* __cplusplus */ #ifdef __cplusplus extern "C" { #endif struct animal; // a nice opaque type struct animal *animal_create(); struct animal *animal_create_init(int age, float height); void animal_destroy(struct animal *a); void animal_setage(struct animal *a, int new_age); void animal_setheight(struct animal *a, float new_height); int animal_getage(struct animal *a); float animal_getheight(struct animal *a); #ifdef __cplusplus } #endif #endif /* ANIMAL_H */

Archivo de implementación animal C ++ - animal.cpp

#include "animal.h" #define TO_CPP(a) (reinterpret_cast<Animal*>(a)) #define TO_C(a) (reinterpret_cast<animal*>(a)) void Animal::setAge(int new_age) { this->age = new_age; } int Animal::getAge() { return this->age; } void Animal::setHeight(float new_height) { this->height = new_height; } float Animal::getHeight() { return this->height; } animal *animal_create() { animal *a = TO_C(new Animal); return a; } animal *animal_create_init(int age, float height) { animal *a = TO_C(new Animal(age, height)); return a; } void animal_destroy(animal *a) { delete TO_CPP(a); } void animal_setage(animal *a, int new_age) { TO_CPP(a)->setAge(new_age); } void animal_setheight(animal *a, float new_height) { TO_CPP(a)->setHeight(new_height); } int animal_getage(animal *a) { TO_CPP(a)->getAge(); } float animal_getheight(animal *a) { TO_CPP(a)->getHeight(); }

C código de cliente - main.c

#include "animal.h" #include <stdio.h> int main() { // 6''0" 25yo (perhaps a human? :P) struct animal *a = animal_create(25, 1.83); animal_setage(a, 26); // birthday printf("Age: %d/nHeight: %f", animal_getage(a), animal_getheight(a)); animal_destroy(a); return 0; }

Código de cliente C ++ - main.cpp

#include "animal.h" #include <iostream> int main() { // 6''0" 25yo (perhaps a human? :P) Animal* a = new Animal(25, 1.83); a->setAge(26); // birthday std::cout << "Age: " << a->getAge() << std::endl; std::cout << "Height: " << a->getHeight(); delete a; return 0; }

Entonces, cuando compila la biblioteca, compila animal.cpp con un compilador C ++. A continuación, puede vincularlo con el código C y usar las funciones animal_xxx .

Tenga en cuenta el uso de struct animal y Animal . Animal es un tipo normal de C ++. Es exactamente lo que parece. struct animal , por otro lado, es un tipo "opaco". Eso significa que su programa C puede ver que está allí, y puede tener uno, pero no sabe qué hay dentro de él. Todo lo que sabe es que tiene una función que toma una struct animal* .

En una biblioteca real, querrá tener puntos de personalización para la asignación de memoria. Asumiendo que esta es la biblioteca libjungle , probablemente quieras al menos jungle_setmalloc y jungle_setfree con valores predeterminados razonables. Luego puede configurar el global new y delete en el libjungle de C ++ de libjungle para usar estas funciones definidas por el usuario.