Я знаю это.
Вызов функции 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
c++
c
visual-c++
extern-c
когти
источник
источник
Ответы:
Вам необходимо создать C API для демонстрации функциональности вашего кода C ++. По сути, вам нужно будет написать код C ++, который объявлен как extern «C» и имеет чистый C API (например, без использования классов), который охватывает библиотеку C ++. Затем вы используете созданную вами чистую библиотеку-оболочку C.
Ваш C API может опционально следовать объектно-ориентированному стилю, даже если 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); }
источник
*.cpp file
I также необходимо , чтобы обернуть функции в#ifdef _cplusplus
+ ,extern "C"
чтобы избежать «неопределенной ссылки на» ошибку во время соединения.Я бы сделал это так:
(При работе с MSVC игнорируйте команды компиляции GCC)
Предположим, что у меня есть класс C ++ с именем AAA , определенный в файлах aaa.h, aaa.cpp , и что у класса AAA есть метод с именем sayHi (const char * name) , который я хочу включить для кода C.
Код C ++ класса AAA - Pure 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 и вызывать его метод:
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 implement functions in C++, which will externally // appear as C functions (which means that the function IDs will be their names, unlike // the regular C++ behavior, which allows defining multiple functions with the same name // (overloading) and hence uses function signature hashing to enforce unique IDs), 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 , я получу ожидаемый результат:
РЕДАКТИРОВАТЬ:
В некоторых дистрибутивах Linux,
-laaa
а-lstdc++
также может потребоваться для выполнения последней команды компиляции. Спасибо @AlaaM. для вниманияисточник
gcc usecpp.c -L. -laaa_c_connector -Wl,-rpath,. -o c_aaa
usecpp.c
?gcc main.c -L. -laaa_c_connector -laaa -lstdc++ -o c_aaa
. Обратите внимание на-laaa
and-lstdc+++
main.c
наusecpp.c
. Я только что отменил его .... Что касается другого комментария, он должен работать как есть. Используется вторая компиляция,-laaa
и этого, вероятно, должно быть достаточно (я написал ее более 1,5 лет назад, я не очень хорошо помню, что я делал, но я думаю, что я тестировал каждую строку перед публикацией)Вам придется написать оболочку для C на C ++, если вы хотите это сделать. C ++ имеет обратную совместимость, но C не поддерживает прямую совместимость.
источник
Предполагая, что C ++ API совместим с C (без классов, шаблонов и т. Д.), Вы можете обернуть его в
extern "C" { ... }
же, как вы это сделали, когда пошли другим путем.Если вы хотите раскрыть объекты и другие милые вещи C ++, вам придется написать API-оболочку.
источник
экспортируйте свои функции C ++ как extern «C» (также известные как символы стиля C) или используйте формат файла .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; }
источник
Вы можете префикс объявления функции с помощью ключевого слова extern «C», например
extern «C» int Mycppfunction ()
{
// Код идет сюда
возврат 0;
}
Дополнительные примеры вы можете найти в Google по ключевому слову extern. Вам нужно сделать еще несколько вещей, но это несложно, вы получите много примеров от Google.
источник