Korzystanie z biblioteki C ++ w kodzie C.

103

Mam bibliotekę C ++, która udostępnia różne klasy do zarządzania danymi. Mam kod źródłowy biblioteki.

Chcę rozszerzyć interfejs API C ++, aby obsługiwał wywołania funkcji C, aby biblioteka mogła być używana z kodem C i kodem C ++ w tym samym czasie.

Używam łańcucha narzędzi GNU (gcc, glibc itp.), Więc obsługa języka i architektury nie stanowi problemu.

Czy są jakieś powody, dla których tak jest technicznie niemożliwe?

Czy są jakieś pułapka, na którą muszę uważać?

Czy są dostępne zasoby, przykładowy kod i / lub dokumentacja na ten temat?


Kilka innych rzeczy, o których się dowiedziałem:

  1. Użyj poniższego, aby zawinąć nagłówki C ++, które muszą być używane przez kod C.

#ifdef __cplusplus
extern "C" {  
#endif  
//  
// Code goes here ...  
//  
#ifdef __cplusplus  
} // extern "C"  
#endif
  1. Przechowuj "prawdziwe" interfejsy C ++ w oddzielnych plikach nagłówkowych, które nie są objęte zasadą C. Pomyśl o PIMPL tutaj o . Używanie #ifndef __cplusplus #errorrzeczy pomaga tutaj wykryć jakiekolwiek szaleństwo.
  2. Uważaj na identyfikatory C ++ jako nazwy w kodzie C.
  3. Wyliczenia różniące się rozmiarem między kompilatorami C i C ++. Prawdopodobnie nie stanowi to problemu, jeśli używasz łańcucha narzędzi GNU, ale mimo to bądź ostrożny.
  4. W przypadku struktur postępuj zgodnie z następującym formularzem, aby C nie pomylił się.

    typedef struct X { ... } X
  5. Następnie użyj wskaźników do przekazywania obiektów C ++, po prostu muszą być zadeklarowane w C jako struktura X, gdzie X jest obiektem C ++.

Wszystko to dzięki uprzejmości przyjaciela, który jest czarodziejem w C ++.

Misha M
źródło
5
Trochę późno, ale napisałem małe howto o opakowaniu C dla C ++: teddy.ch/c++_library_in_c
Teddy.

Odpowiedzi:

69

Tak, z pewnością jest to możliwe. Będziesz musiał napisać warstwę interfejsu w C ++, która deklaruje funkcje z extern "C":

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

Następnie zadzwonisz foo()z modułu C, który przekaże wywołanie dorealFoo() funkcji zaimplementowanej w C ++.

Jeśli chcesz udostępnić pełną klasę C ++ ze składowymi danych i metodami, być może będziesz musiał wykonać więcej pracy niż ten prosty przykład funkcji.

Greg Hewgill
źródło
Czy extern "C"należy umieszczać je tylko w deklaracjach (a nie w definicjach)? Ponieważ wspomniałeś o „warstwie, która deklaruje funkcje”, ale Twój przykładowy kod jest również definicją. Innymi słowy, czy powinniśmy umieścić go w plikach nagłówkowych czy źródłowych? (Lub obu?)
kyriakosSt
@KyrSt: Jeśli masz plik nagłówkowy z deklaracją funkcji, musisz go przynajmniej umieścić extern "C". Twój kompilator powie ci, czy musisz również umieścić to w definicji.
Greg Hewgill,
23

C ++ FAQ Lite: „Jak mieszać kod C i C ++” .

Niektóre problemy opisano w odpowiedziach na następujące pytania:

  • [32.8] Jak mogę przekazać obiekt klasy C ++ do / z funkcji C?
  • [32.9] Czy moja funkcja C może mieć bezpośredni dostęp do danych w obiekcie klasy C ++?
Alex B.
źródło
12

Główny problem: wyjątków nie można przechwytywać w C. Jeśli istnieje możliwość wystąpienia wyjątku w kodzie C ++, należy bardzo uważnie napisać swój kod C lub opakowania C ++. I odwrotnie, mechanizmy typu wyjątków (tj. Longjump) w kodzie C (występujące w różnych językach skryptowych) nie są wymagane do wywoływania destruktorów obiektów C ++ na stosie.

ejgottl
źródło
2
Świetna uwaga na temat długich skoków. Chociaż nie używam ich bezpośrednio, platformy testowe, których używam, implementują je. Coś, o czym warto pamiętać. Dzięki
Misha M,
3

możesz mieszać kod C / C ++. Jeśli twoja funkcja main () jest w C ++, wystarczy upewnić się, że funkcje c są zadeklarowane

extern "C"

Jeśli Twoim głównym jest C, prawdopodobnie wszystko jest w porządku, z wyjątkiem zmiennych statycznych. Wszelkie konstruktory ze zmiennymi statycznymi powinny być wywoływane przed uruchomieniem funkcji main (). To się nie stanie, jeśli C jest Twoim głównym. Jeśli masz dużo zmiennych statycznych, najlepiej jest zamienić zmienne statyczne na pojedyncze.

David Nehme
źródło