Використання бібліотеки C ++ у коді С


102

У мене є бібліотека 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. Keep інтерфейси «реальний» C ++ в окремих файлах заголовків, які не включені по C. Подумайте принцип Pimpl тут. Використання#ifndef __cplusplus #error матеріалів допомагає виявити будь-яку божевільність.
  2. Обережно до ідентифікаторів С ++ як імен у коді С
  3. Перерахування різного розміру між компіляторами C та C ++. Можливо, це не проблема, якщо ви використовуєте ланцюжок інструментів GNU, але все ж будьте обережні.
  4. Для конструкцій дотримуйтесь наступної форми, щоб C не заплутався.

    typedef struct X { ... } X
  5. Потім використовуйте покажчики для переходу навколо об'єктів C ++, їх просто потрібно оголосити в C як структуру X, де X - об'єкт C ++.

Все це - люб’язність друга, який є майстром на C ++.


5
Трохи пізно, але я написав невеликий хау-хат
Тедді

Відповіді:


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 ++ до / з функції С?
  • [32.9] Чи може моя функція C безпосередньо отримувати доступ до даних в об'єкті класу C ++?

11

Основний прийом: винятки не можна назвати C. Якщо є можливість винятку, що збільшується в коді C ++, або дуже обережно напишіть свій код C або ваші обгортки C ++. І навпаки, такі механізми, як винятки (тобто longjump) у коді C (як це можна знайти в різних мовах скриптів), не вимагають викликати деструктори для об'єктів C ++ у стеці.


2
Відмінна думка про дзвінки з longjump. Хоча я не використовую їх безпосередньо, тестові рамки, які я використовую, реалізують їх. Щось слід пам’ятати. Спасибі
Міша М

3

ви можете змішати код C / C ++. Якщо ваша основна () функція входить у C ++, вам просто потрібно переконатися, що ваші функції c оголошені

extern "C"

Якщо ваш головний C, ви, ймовірно, добре, за винятком статичних змінних. Будь-які конструктори зі своїми статичними змінними повинні бути викликані перед початком main (). Це не відбудеться, якщо C - ваш головний. У вас є багато статичних змінних, найкраще зробити це замінити статичні змінні одинаковими.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.