Как вызвать библиотеку, написанную на C ++ из C? - PullRequest
2 голосов
/ 25 октября 2010

Мне кажется, что это легко, но я не могу найти никакой информации против или за нее.

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

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

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

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

Ответы [ 7 ]

8 голосов
/ 25 октября 2010

Как правило, вам нужно заставить компилятор 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" недопустимо в C.

ОБНОВЛЕНИЕ

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

4 голосов
/ 25 октября 2010

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

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

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

3 голосов
/ 25 октября 2010

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

2 голосов
/ 25 октября 2010

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

nm my-tiny-c++lib.a

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

Редактировать : тогда вам нужно связать, используя g ++ или gcc -lstdc ++

2 голосов
/ 25 октября 2010

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

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

1 голос
/ 25 октября 2010

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

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

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

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

Для всех ваших функций Си.только в шапке поставить

#ifdef __cplusplus
extern "C" {
#endif

// all your functions

#ifdef __cplusplus
}
#endif
0 голосов
/ 26 октября 2010

Типичная оболочка выглядит так:

---- 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);
}
...