2010-10-25 2 views
2

Мне кажется, как без проблем, но я не могу найти никакой информации против или для нее.Как вызвать lib, написанный на C++ с C?

С точки зрения демонтажа и т. Д., Я не думаю, что это большая проблема, но я не могу понять, как я могу написать небольшую крошечную программу на C, которая вызывает функцию от маленького крошечного Библиотека C++.

Я нахожусь на linux прямо сейчас, пытаясь со статическим привязкой.

Это должно быть что-то много людей, которые сталкиваются или покрывают многие обложки книг, но я чувствую себя слепой, сидящей перед этой проблемой. Интересно, что на SO тоже нет такого вопроса.

Я даже не знаю, ЕСЛИ это может работать, гораздо меньше, КАК это должно быть сделано.

+0

спасибо всем, кто отвечает (и так быстро :). Я думал о «extern» C », но я рассуждал неправильно, что это было только наоборот. Работает, как шарм, конечно, – lImbus

ответ

8

Как правило, необходимо принудительно заставить компилятор C++ создавать библиотеку с помощью C-ссылки для экспортированных функций.

Вы можете сделать это, выполнив следующие действия в ваш заголовок:

#ifdef __cplusplus 
extern "C" { 
#endif 

void func(void); 

/* ... Other function defs go here ... */ 

#ifdef __cplusplus 
} 
#endif 

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

UPDATE

Как говорит Чарльз Salvia в комментарии ниже, вы должны убедиться, что никаких исключений не пробиваются через ваш интерфейс, потому что C не имеет возможности обрабатывать их (по крайней мере, не независимо от платформы).

+1

Просто будьте осторожны, что 'func' не бросает никаких неперехваченных исключений C++, которые распространяются через C-код. –

+0

@Charles Salvia, хорошая идея, но как это будет хуже, чем неперехваченное исключение в C++, они оба приведут к сбою. – mikerobi

+0

Ì предложите изменить объявление функции на 'void func (void) NOTHROW;' с условными определениями '#define NOTHROW' в режиме C и' #define NOTHROW throw() 'в режиме C++ – Christoph

2

Это проблема с точки деманлинга. Используйте extern C вокруг C++, который вы хотите вызвать от C.

Mangling and de-mangling не был стандартизован на C++, так как он считался слишком зависимым от платформы. В результате получается, что, хотя вы можете определить имя метода метода C++, просмотрев вывод компоновщика, нет никакого переносного способа поиска «реального» связующего имени метода C++.

4

Если библиотека C++ не предоставляет интерфейс C, то вы не можете.

Если это так, используйте интерфейс C.

Если вы являетесь автором, воспользуйтесь функцией extern "C". http://www.parashift.com/c++-faq-lite/mixing-c-and-cpp.html

+1

Вы/can /, это просто больно и очень, ОЧЕНЬ зависит от компилятора, включая версию компилятора. – Arafangion

3

Лично я бы написал файл на C++, который экспортирует функции, которые используют связь C. Другими словами, напишите привязку.

+0

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

2

В Linux, вы можете получить искаженное имя ваших функций C++ с помощью команды

nm my-tiny-c++lib.a 

Вызов функции из С, это искаженное имя, но не ожидаем, что этот трюк, чтобы быть портативным ...

Редактировать: тогда вы должны связать с помощью г ++, или с GCC -lstdC++

+1

Это был очень интересный хак, чтобы проверить, в какую битву я сражался. Я знал nm и проверял lib уже для поиска каких-либо подсказок, но не имел идеи назвать функцию с этим именем. – lImbus

1

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

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

Теперь вы создаете свободные функции для создания указателя на такую ​​структуру (а не экземпляр, поскольку вы не видите его полного определения), и распоряжаться таким указателем и всеми его методами, взяв его как параметр ,

Обратите внимание, что если класс находится в пространстве имен, вы не сможете этого сделать, создайте свою собственную структуру, которая имеет только этот член, и вместо этого используйте эту «обертку».

Для всех ваших функций C. только заголовок, положить

#ifdef __cplusplus 
extern "C" { 
#endif 

// all your functions 

#ifdef __cplusplus 
} 
#endif 
0

Типичный обертка выглядит следующим образом:

---- class_a.hpp ----

#include "class_a_wrapper" 

class A { 
    public: 
    int foo(double p); 
    double bar(int x, int y); 
} 

---- class_a_wrapper.h - -

#ifdef __cplusplus 
extern "C" { 
#endif 

struct wrap_A; 
int wrap_A_foo(struct wrap_A *obj, double p); 
double wrap_A_bar(struct wrap_A *obj, int x, int y); 

#ifdef __cplusplus 
} 
#endif 

---- class_a_wrapper.cpp ----

#include "class_a.hpp" 

int wrap_A_foo(struct wrap_A *obj, double p) { 
    return (static_cast<A*>obj)->foo(p); 
} 
double wrap_A_bar(struct wrap_A *obj, int x, int y) { 
    return (static_cast<A*>obj)->bar(x, y); 
}