Использование библиотеки C ++ в коде C

103

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

Я хочу расширить API C ++ для поддержки вызовов функций C, чтобы библиотеку можно было использовать с кодом C и кодом C ++ одновременно.

Я использую цепочку инструментов GNU (gcc, glibc и т. Д.), Поэтому поддержка языка и архитектуры не является проблемой.

Есть ли причины, по которым это технически невозможно?

Есть ли какие-то проблемы, которых мне нужно остерегаться?

Есть ли по этому поводу ресурсы, примеры кода и / или документация?


Еще кое-что, что я выяснил:

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

#ifdef __cplusplus
extern "C" {  
#endif  
//  
// Code goes here ...  
//  
#ifdef __cplusplus  
} // extern "C"  
#endif
  1. Храните «настоящие» интерфейсы C ++ в отдельных файлах заголовков, которые не включены в C. Подумайте о принципе PIMPL . Использование #ifndef __cplusplus #errorвещей помогает здесь обнаружить любое безумие.
  2. Осторожно с идентификаторами C ++ как именами в коде C
  3. Перечисления различаются по размеру в компиляторах C и C ++. Возможно, это не проблема, если вы используете цепочку инструментов GNU, но все же будьте осторожны.
  4. Для структур используйте следующую форму, чтобы не запутать C.

    typedef struct X { ... } X
  5. Затем используйте указатели для передачи объектов C ++, их просто нужно объявить в C как struct X, где X - объект C ++.

Все это любезно предоставил друг, который специализируется на C ++.

Миша М
источник
5
Немного поздно, но я написал небольшое руководство
Teddy

Ответы:

69

Да, конечно, это возможно. Вам нужно будет написать уровень интерфейса на C ++, который объявляет функции с extern "C":

extern "C" int foo(char *bar)
{
    return realFoo(std::string(bar));
}

Затем вы вызовете foo()из своего модуля C, который передаст вызов realFoo()функции, реализованной на C ++.

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

Грег Хьюгилл
источник
Следует extern "C"размещать только в объявлениях (а не в определениях)? Поскольку вы упомянули «уровень, объявляющий функции», но ваш пример кода также является определением. Другими словами, следует ли размещать его в файлах заголовков или исходных файлах? (Или в обоих?)
kyriakosSt
@KyrSt: Если у вас есть файл заголовка с объявлением функции, то вы должны хотя бы extern "C"туда поместить . Ваш компилятор сообщит вам, нужно ли вам также добавить его в определение.
Грег Хьюгилл
23

C ++ FAQ Lite: «Как смешивать код C и C ++» .

Некоторые ошибки описаны в ответах на эти вопросы:

  • [32.8] Как передать объект класса C ++ в / из функции C?
  • [32.9] Может ли моя функция C напрямую обращаться к данным в объекте класса C ++?
Алекс Б
источник
12

Основная проблема: исключения не могут быть перехвачены в C.Если есть вероятность возникновения исключения в коде C ++, очень осторожно напишите свой код C или свои оболочки C ++. И наоборот, механизмы, подобные исключениям (например, longjump) в коде C (как в различных языках сценариев), не требуются для вызова деструкторов для объектов C ++ в стеке.

Ejgottl
источник
2
Отличный момент о коллах в длинном прыжке. Хотя я не использую их напрямую, используемые мной среды тестирования реализуют их. Что нужно иметь в виду. Спасибо
Misha M
3

вы можете смешивать код C / C ++. Если ваша функция main () на C ++, вам просто нужно убедиться, что ваши функции c объявлены

extern "C"

Если ваш main - C, то вы, вероятно, в порядке, за исключением статических переменных. Любые конструкторы с вашими статическими переменными должны вызываться перед запуском main (). Этого не произойдет, если C - ваш main. Если у вас много статических переменных, лучше всего заменить статические переменные одиночными.

Дэвид Нехме
источник