2010-04-30 2 views
48

Я знаю это.Как вызвать функцию 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. 

Это Wouldn» t mangle имя C_library_function и компоновщик найдет то же имя в своих файлах ввода * .lib и проблема будет решена.

Вызов функции C++ с C ???

Но здесь я расширяю большое приложение, написанное на C, и мне нужно использовать библиотеку, написанную на C++. Вызывается проблема с изменением имени C++. Линкер жалуется на неразрешенные символы. Ну, я не могу использовать компилятор C++ над моим проектом C, потому что это ломает много других вещей. Каков выход?

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

+4

Прочтите http://www.parashift.com/c++-faq-lite/mixing-c-and-cpp.html#faq-32.6 – jweyrich

+0

Когда вы управляете библиотекой C++: http: // stackoverflow. com/questions/12615683/call-c-functions-from-c-file –

+2

Возможный дубликат [Элегантный вызов C++ с C] (http://stackoverflow.com/questions/7281441/elegantly-call-c-from-c) – user2284570

ответ

59

Вам необходимо создать API C для раскрытия функциональности вашего кода на C++. В принципе, вам нужно будет написать код на C++, который объявлен extern «C» и имеет чистый C API (например, не использует классы), который обертывает библиотеку 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); 
} 
+0

спасибо !! понял. http://www.parashift.com/c++-faq-lite/mixing-c-and-cpp.html#faq-32.6 – claws

+1

Спасибо за ответ. Однако ссылка не работает. – Milo

+1

Спасибо. Не понял, что по-прежнему были ссылки на эту страницу из StackOverlow, когда я удалил ее. Я обновил ответ, чтобы предоставить более подробную информацию, не ссылаясь на эту страницу. –

2

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

5

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

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

+0

Не совсем ... библиотеку C++ нужно перекомпилировать. –

+0

О нет. C++ API полностью объектно-ориентирован. – claws

+2

@claws, см. Мою статью о создании кода C кода OOP .. и создайте библиотеку-оболочку, используя этот стиль с интерфейсом C, но лежащую в основе C++-реализацию. Затем ссылку на интерфейс C. –

5

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

17

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

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

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

код C++ класса AAA - Pure C++, я не изменить его:

// ааа.ч

#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 символ * имя), который будет использовать экземпляр 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 

компиляция это, опять же, с помощью обычного C++ команда компиляции:

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

Теперь у меня есть общая библиотека (libaaa_c_connector.so), которая реализует функцию C AAA_sayHi (Const символ * имя). Теперь я могу создать главный файл 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. для внимания

+1

Большое вам спасибо. Ваш подробный ответ мне очень помог. – Abhinav

+1

вы также можете указать путь к ссылке lib с помощью 'gcc usecpp.c -L. -laaa_c_connector -Wl, -rpath ,. -o c_aaa' – Metaphox

+0

Что такое 'usecpp.c'? –

Смежные вопросы