Как вызвать функцию С++ из 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, потому что это ломает много других вещей. Каков выход?

Кстати, я использую MSVC

45
30 апр. '10 в 14:36
источник поделиться
5 ответов

Вам нужно создать API-интерфейс C для отображения функциональности вашего кода на С++. В принципе, вам нужно будет написать код на С++, который объявлен extern "C" и имеет чистый C API (например, не использует классы), который обертывает библиотеку С++. Затем вы используете созданную вами библиотеку оболочек pure C.

Ваш API-интерфейс 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);
 }
58
30 апр. '10 в 14:41
источник

Связанные вопросы


Похожие вопросы

Я бы сделал это следующим образом:

(Если вы работаете с MSVC, игнорируйте команды компиляции GCC)

Предположим, что у меня есть класс С++ с именем AAA, определенный в файлах aaa.h, aaa.cpp и что класс AAA имеет метод с именем sayHi (const char * name), который я хочу включить для кода C.

Код класса С++ AAA - Pure С++, я не изменяю его:

//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. Используя команду:

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

Теперь, также на С++, создаем 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 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

Скомпилировав его, снова с помощью обычной команды компиляции С++:

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 James

EDIT:

В некоторых дистрибутивах Linux для последней команды компиляции также может потребоваться -laaa и -lstdc++. Благодаря @AlaaM. для внимания

15
22 марта '15 в 12:37
источник

Вам нужно написать оболочку для C на С++, если вы хотите это сделать. С++ совместим с обратной совместимостью, но C не совместим с версией.

5
30 апр. '10 в 14:43
источник

Предполагая, что С++ API является C-совместимым (без классов, шаблонов и т.д.), вы можете обернуть его в extern "C" { ... }, как вы это делали, идя другим путем.

Если вы хотите выставить объекты и другие симпатичные материалы С++, вам придется написать API-интерфейс обертки.

5
30 апр. '10 в 14:41
источник

экспортируйте свои С++-функции как extern "C" (например, символы стиля C) или используйте формат файла .def для определения неэкспортированных символов экспорта для С++-компоновщика при создании библиотеки С++, тогда C-компоновщик не должен иметь проблем чтение его

2
30 апр. '10 в 14:40
источник

Посмотрите другие вопросы по меткам или Задайте вопрос