2010-04-30 25 views
48

Ich weiß das.Wie C++ Funktion von C aufrufen?

Aufruf C-Funktion von C++:

Wenn mein Antrag wurde in C++ und ich hatte Funktionen aus einer Bibliothek in C geschrieben anrufen Dann würde ich

//main.cpp 

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

Dieses wouldn‘verwendet habe t mangle den Namen C_library_function und Linker würde den gleichen Namen in seiner Eingabe finden * .lib-Dateien und das Problem ist gelöst.

Aufruf C++ Funktion von C ???

Aber hier erweitern ich eine große Anwendung, die in C geschrieben ist und ich brauche eine Bibliothek, die in C++ geschrieben ist. Der Name Mangling von C++ verursacht hier Probleme. Linker beschwert sich über die ungelösten Symbole. Nun, ich kann den C++ - Compiler nicht über mein C-Projekt benutzen, weil das viele andere Dinge kaputt macht. Was ist der Ausweg?

Durch die Art, wie ich MSVC bin mit

+4

lesen http://www.parashift.com/c++-faq-lite/mixing-c-and-cpp.html#faq-32.6 – jweyrich

+0

Wenn steuern Sie die C++ Bibliothek: http: // Stackoverflow. com/questions/12615683/aufrufende-c-functions-from-c-datei –

+2

Mögliches Duplikat von [Elegant Call C++ aus C] (http://stackoverflow.com/questions/7281441/elegantly-call-c-from-c) – user2284570

Antwort

59

Sie müssen eine C-API erstellen, um die Funktionalität Ihres C++ - Codes verfügbar zu machen. Im Grunde müssen Sie C++ - Code schreiben, der extern "C" deklariert ist und der eine reine C-API hat (die beispielsweise keine Klassen verwendet), die die C++ - Bibliothek umschließt. Dann verwenden Sie die reine C-Wrapper-Bibliothek, die Sie erstellt haben.

Ihre C-API kann optional einem objektorientierten Stil folgen, obwohl C nicht objektorientiert ist. 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); 
} 
+0

danke !! Ich habs. http://www.parashift.com/c++faq-lite/mixing-c-and-cpp.html#faq-32.6 – claws

+1

Danke für die Antwort. Die Verbindung ist jedoch unterbrochen. – Milo

+1

Danke. Ich habe nicht bemerkt, dass es immer noch Links zu dieser Seite von StackOverlow gab, als ich es löschte. Ich habe die Antwort aktualisiert, um mehr Details zu geben, ohne auf diese Seite zu verweisen. –

2

Export Ihre C++ Funktionen wie extern „C“ (auch bekannt als C-Stil Symbole), oder verwenden Sie das DEF-Datei-Format undecorated Exportsymbole für die C++ Linker, wenn es zu definieren, erstellt die C++ - Bibliothek, dann sollte der C-Linker keine Probleme haben, sie zu lesen

5

den C++ API Unter der Annahme, C-kompatibel (keine Klassen, Vorlagen, etc.), können Sie sie wickeln in extern "C" { ... }, genau wie damals, als in die andere Richtung.

Wenn Sie Objekte und andere niedliche C++ Zeug verfügbar machen möchten, müssen Sie eine Wrapper-API schreiben.

+0

Nicht ganz ... die C++ - Bibliothek müsste neu kompiliert werden. –

+0

Oh nein. C++ API ist vollständig objektorientiert. – claws

+2

@claws, siehe meinen Artikel über OOP-Stil C-Code .. und erstellen Sie eine Wrapper-Bibliothek mit diesem Stil mit einer C-Schnittstelle, sondern eine zugrunde liegende C++ - Implementierung. Verknüpfen Sie dann mit der C-Schnittstelle. –

5

Sie müssen einen Wrapper für C in C++ schreiben, wenn Sie dies tun möchten. C++ ist abwärtskompatibel, aber C ist nicht vorwärtskompatibel.

17

Ich würde es auf folgende Weise tun:

(Wenn mit MSVC arbeiten, ignorieren Sie die GCC Kompilation Befehle)

Nehmen wir an, ich habe eine C++ Klasse mit dem Namen AAA, definiert in Dateien aaa .h, aaa.cpp, und dass die Klasse AAA eine Methode namens sayHi (const char * name) hat, die ich für C-Code aktivieren möchte.

Der C++ Code der Klasse AAA - Pure C++, ich nicht ändern es:

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

diese Klasse kompilieren, wie regelmäßig für C++ getan. Dieser Code "weiß nicht", dass er von C-Code verwendet wird. Mit dem Befehl:

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

nun auch in C++, C-Anschluss zu schaffen. Definieren in Dateien aaa_c_connector.h, aaa_c_connector.cpp. Dieser Anschluss wird eine C-Funktion definieren, (Name cosnt char *) AAA_sayHi namens, die eine Instanz von AAA wird verwenden und wird seine Methode aufrufen:

// 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 

es Kompilieren wieder Befehl eines regulären C++ Compilation mit:

g++ -fpic -shared aaa_c_connector.cpp -L. -laaa -o libaaa_c_connector.so 

Jetzt habe ich eine Shared Library (libaaa_c_connector.so), die die C-Funktion implementiert AAA_sayHi (const char * name). Ich kann jetzt eine C Haupt-Datei erstellen und kompilieren sie alle zusammen:

// main.c

#include "aaa_c_connector.h" 

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

    return 0; 
} 

Kompilieren eine C Kompilation Befehl:

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

Ich muss eingestellt LD_LIBRARY_PATH enthalten $ PWD, und wenn ich die ausführbare Datei ausführen ./c_aaa, werde ich den Ausgang ich erwarten:

Hi David 
Hi James 

EDIT:

Auf einigen Linux-Distributionen, -laaa und -lstdc++ auch für den letzten Kompilierung Befehl erforderlich. Danke an @AlaaM. für die Aufmerksamkeit

+1

Vielen Dank so sehr. Ihre ausführliche Antwort hat mir sehr geholfen. – Abhinav

+1

können Sie auch den lib-Linkpfad mit 'gcc usecpp.c -L angeben. -laaa_c_connector -Wl, -rpath ,. -o c_aaa' – Metaphox

+0

Was ist 'usecpp.c'? –

Verwandte Themen