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:
- Agregue
#include <stdio.h>
encmain.c
. - Use
std::string S(filename);
encppfile.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?
- Los únicos datos que estaría pasando y devolviendo serían los tipos de datos compatibles con C.
- 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.