Как вызвать функцию C++ из C?
Я знаю это.
вызов функции C из C++:
Если бы мое приложение было на C++ , и мне пришлось вызывать функции из библиотеки, написанной на C. Тогда я бы использовал
//main.cpp
extern "C" void C_library_function(int x, int y);//prototype
C_library_function(2,4);// directly using it.
это не испортит имя C_library_function и компоновщик найдет то же имя в своем входе *.lib файлы и проблема решена.
вызов функции C++ из C???
но здесь я расширяю большое приложение, которое является написан на C, и мне нужно использовать библиотеку, которая написана на C++. Имя искажение C++ вызывает проблемы здесь. Линкер жалуется на неразрешенные символы. Ну, я не могу использовать компилятор C++ над моим проектом C, потому что это нарушает много других вещей. Каков же выход?
кстати я использую MSVC
6 ответов:
вам нужно создать C API для предоставления функциональности вашего кода на C++. В принципе, вам нужно будет написать код C++, который объявлен extern "C" и который имеет чистый API C (не используя классы, например), который обертывает библиотеку C++. Затем вы используете чистую библиотеку оболочки C, которую вы создали.
ваш API C может дополнительно следовать объектно-ориентированному стилю, даже если C не является объектно-ориентированным. Например:
// *.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); }
Я бы сделал это следующим образом:
(при работе с MSVC игнорируйте команды компиляции GCC)
предположим, что у меня есть класс C++ с именем ААА, определенными в файлах ААА.х, ААА.cpp, а то класс ААА есть метод с именем sayHi (const char * name), что я хочу включить для C-кода.
код класса C++ААА - чистый C++, я не изменяю это:
/ / 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; }компиляция этого класса, как обычно делается для C++. Этот код "не знает", что он будет использоваться код C. С помощью команды:
g++ -fpic -shared aaa.cpp -o libaaa.so
теперь, также В C++, создание соединителя C. Определение его в файлах aaa_c_connector.h, aaa_c_connector.cpp. Этот соединитель будет определять функцию C с именем AAA_sayHi (cosnt char *name), что будет использовать экземпляр ААА и вызовет свой метод:
/ / 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компиляция его, опять же, с помощью обычной команды компиляции C++:
g++ -fpic -shared aaa_c_connector.cpp -L. -laaa -o libaaa_c_connector.so
теперь у меня есть общая библиотека (libaaa_c_connector.so), что реализует функцию C AAA_sayHi (const char *name). Теперь я могу создать основной файл C и скомпилировать все вместе:
/ / main.c
#include "aaa_c_connector.h" int main() { AAA_sayHi("David"); AAA_sayHi("James"); return 0; }компиляция с помощью команды компиляции C:
gcc main.c -L. -laaa_c_connector -o c_aaaмне нужно будет установить LD_LIBRARY_PATH, чтобы содержать $PWD, и если я запускаю исполняемый файл ./c_aaa, я получу результат, который я ожидаю:
Hi David Hi JamesEDIT:
в некоторых дистрибутивах Linux
-laaaи-lstdc++также может потребоваться для последней команды компиляции. Спасибо @AlaaM. за внимание
предполагая, что API C++ совместим с C (без классов, шаблонов и т. д.), вы можете обернуть его в
extern "C" { ... }, Так же, как вы делали, когда шли в другую сторону.Если вы хотите выставить объекты и другие милые вещи C++, вам придется написать API-интерфейс оболочки.
вам придется написать обертку для C в C++ , если вы хотите это сделать. C++ является обратная совместимость, но не вперед совместимы.
экспортируйте свои функции C++ как extern " C " (aka C style symbols) или используйте .формат файла def для определения недекорированных символов экспорта для компоновщика C++ при создании библиотеки C++, тогда компоновщик C не должен иметь проблем с его чтением
#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; }
Comments