Come chiamare un lib scritto in C ++ da C?
-
26-09-2019 - |
Domanda
Mi sembra come un gioco da ragazzi, ma non riesco a trovare tutte le informazioni contro o per esso.
Dal punto di vista della demangling ecc, non credo che questo sia un grosso problema, ma non riesco a capire, come posso scrivere un po 'piccolo programma C che chiama una funzione da un po' piccola C ++ biblioteca.
Sono su linux in questo momento, provando con statico vincolante.
Questo deve essere qualcosa che molte persone sono in esecuzione in molti libri o di copertura, ma mi sento come un Gump cieco seduto di fronte a questo problema. È interessante notare che non esiste una domanda su SO sia.
Io non so nemmeno se questo può funzionare, di gran lunga inferiore come questo ha da fare.
Soluzione
In genere, è necessario forzare il compilatore C ++ per costruire biblioteca collegamento C per le funzioni esportate.
Si può farlo effettuando le seguenti operazioni per l'intestazione:
#ifdef __cplusplus
extern "C" {
#endif
void func(void);
/* ... Other function defs go here ... */
#ifdef __cplusplus
}
#endif
In genere, il linker farà C ++ nome-mutilazione alle funzioni, in modo che il linker C non sarà in grado di trovarli. extern "C"
costringe di non farlo. Hai bisogno di avvolgerlo nel #ifdef
, perché extern "C"
non è valido C.
Aggiorna
Come Charles Salvia dice in un commento qui sotto, è necessario assicurarsi che non si smentisce mai si fanno strada attraverso l'interfaccia, in quanto C non ha modo di loro (almeno non un modo indipendente dalla piattaforma) gestione.
Altri suggerimenti
Se la libreria C ++ non fornisce un'interfaccia C, quindi non è possibile.
Se è così, l'interfaccia uso C.
Se sei l'autore, utilizzare la funzione extern "C"
. http://www.parashift.com/c++-faq -lite / mixing-c-e-cpp.html
Personalmente, mi piacerebbe scrivere un file C ++ che esporta funzioni che utilizzano C linkage. In altre parole, scrivere un vincolante.
Su Linux, è possibile ottenere il nome storpiato del C ++ funzioni con il comando
nm my-tiny-c++lib.a
Chiama la funzione da C per il suo nome storpiato, ma non aspettatevi questo trucco per essere portabile ...
Modifica : poi si deve collegamento mediante g ++, oppure con gcc -lstdc ++
Si tratta di un problema dal punto di demangling. Usa extern C intorno al C ++ che si desidera chiamare da C.
pressare e de-pressare non è mai stata standardizzata in C ++, in quanto si è ritenuto troppo dipendente dalla piattaforma . Il risultato è che, mentre si potrebbe capire il nome del metodo di un metodo C ++, cercando in uscita linker, non c'è modo portatile di trovare il "vero" nome collegabile di un metodo di funzione di C ++.
È possibile scrivere un wrapper C intorno a qualsiasi libreria C ++ che ha un'API C ++. L'involucro deve essere scritto in C ++.
È anche possibile utilizzare le classi C ++. È in avanti li dichiara come struct. Alcuni compilatori darà un avvertimento se si fa questo, ma probabilmente si può disabilitare o l'avviso o semplicemente ignorarlo.
È ora di creare liberi funzioni per creare un puntatore a tale struct (non un caso, come non si vede la sua piena definizione) e disporre di un tale puntatore e tutti i suoi metodi prendendo come parametro.
Si noti che se la classe è in uno spazio dei nomi, non si sarà in grado di fare questo in modo creare il proprio struct che ha proprio questo membro e l'uso che "wrapper", invece.
Per tutte le funzioni C. nell'intestazione solo, mettere
#ifdef __cplusplus
extern "C" {
#endif
// all your functions
#ifdef __cplusplus
}
#endif
tipici sguardi involucro come questo:
---- ---- class_a.hpp
#include "class_a_wrapper"
class A {
public:
int foo(double p);
double bar(int x, int y);
}
---- ---- class_a_wrapper.h
#ifdef __cplusplus
extern "C" {
#endif
struct wrap_A;
int wrap_A_foo(struct wrap_A *obj, double p);
double wrap_A_bar(struct wrap_A *obj, int x, int y);
#ifdef __cplusplus
}
#endif
---- ---- class_a_wrapper.cpp
#include "class_a.hpp"
int wrap_A_foo(struct wrap_A *obj, double p) {
return (static_cast<A*>obj)->foo(p);
}
double wrap_A_bar(struct wrap_A *obj, int x, int y) {
return (static_cast<A*>obj)->bar(x, y);
}