Łączenie C++ i C-jak działa # ifdef cplusplus?
Pracuję nad projektem, który ma spore dziedzictwo C kodu. Zaczęliśmy pisać w C++, z zamiarem ostatecznie przekonwertowania kodu starszego. Jestem trochę zdezorientowany, jak C i C++ współdziałają. Rozumiem, że zawijając kod C z extern "C"
kompilator C++ nie zmieni nazw kodu C , ale nie jestem do końca pewien, jak to zaimplementować.
Tak więc na górze każdego C pliku nagłówkowego (po include guards), mamy
#ifdef __cplusplus
extern "C" {
#endif
I na dole piszemy
#ifdef __cplusplus
}
#endif
Pomiędzy tymi dwoma, mamy wszystkie nasze includes, typedefs i prototypy funkcji. Mam kilka pytań, aby sprawdzić, czy dobrze to Rozumiem: {]}
Jeśli mam plik C++ A. hh który zawiera plik nagłówkowy C B. h, zawiera inny C plik nagłówkowy C. h, jak to działa? Myślę, że gdy kompilator wchodzi w B. h,
__cplusplus
zostanie zdefiniowana, więc Wola zawiń kod za pomocąextern "C"
(i__cplusplus
nie będzie zdefiniowanych wewnątrz tego bloku). Więc, kiedy wchodzi do C. h,__cplusplus
nie zostanie zdefiniowana a kod nie będzie owinięty wextern "C"
. Czy to prawda?Czy coś jest nie tak z owijanie kawałka kodu z
extern "C" { extern "C" { .. } }
? Co będzie drugieextern "C"
zrobić?Nie kładziemy tego opakowania wokół .pliki c, tylko ... pliki H. Co się stanie, jeśli funkcja nie ma prototypu? Czy kompilator uważa, że jest to Funkcja C++?
Korzystamy również z usług osób trzecich kod, który jest zapisany w C i robi nie mam takiego opakowania to. Za każdym razem dołączam nagłówek z tej biblioteki, wkładałem an
extern "C"
wokół # include. Czy to właściwy sposób radzenia sobie z to?Wreszcie, czy to jest dobry pomysł? Czy jest coś jeszcze, co powinniśmy zrobić? Będziemy mieszać C i C++ w przewidywalnej przyszłości, a ja chcesz się upewnić zajmujemy się wszystkim nasze bazy.
3 answers
extern "C"
to nie zmienia sposobu, w jaki kompilator odczytuje kod. Jeśli twój kod jest w .plik c, zostanie skompilowany jako C, jeśli znajduje się wplik cpp, zostanie skompilowany jako C++ (chyba, że zrobisz coś dziwnego w konfiguracji).
To, co extern "C"
ma wpływ na połączenie. Funkcje C++, po skompilowaniu, mają swoje nazwy zniekształcone - to sprawia, że przeciążenie jest możliwe. Nazwa funkcji jest modyfikowana na podstawie typów i liczby parametrów, tak aby dwie funkcje z ta sama nazwa będzie miała różne nazwy symboli.
Kod wewnątrz {[0] } jest nadal kodem C++. Istnieją ograniczenia co do tego, co można zrobić w bloku extern "C", ale wszystkie dotyczą linkowania. Nie można zdefiniować żadnych nowych symboli, które nie mogą być budowane za pomocą C linkage. Oznacza to na przykład brak klas lub szablonów.
extern "C"
klocki ładnie gniazdują. Jest też extern "C++"
jeśli znajdziesz się beznadziejnie uwięziony wewnątrz extern "C"
regionów, ale to nie jest taki dobry pomysł z czystości perspektywa.
Regarding #1: _ _ cplusplus powinien być zdefiniowany wewnątrz extern "C"
bloków. Nie ma to jednak znaczenia, ponieważ bloki powinny dobrze zagnieżdżać się.
Odnośnie #2: _ _ cplusplus będzie zdefiniowany dla każdej jednostki kompilacji, która jest uruchamiana przez kompilator C++. Ogólnie to znaczy .pliki cpp i wszelkie pliki dołączane przez to .plik cpp. To samo .h (lub .hh lub .hpp czy co-masz - ty) może być interpretowane jako C lub c++ w różnym czasie, jeśli zawierają je różne jednostki kompilacji. Jeśli chcesz prototypy w .plik h, aby odnosić się do nazw symboli C, musi mieć extern "C"
, gdy jest interpretowany jako C++, a nie powinien mieć extern "C"
, gdy jest interpretowany jako C -- stąd sprawdzanie #ifdef __cplusplus
.
Aby odpowiedzieć na twoje pytanie #3: Funkcje Bez prototypów będą miały łącze C++, jeśli są w .pliki cpp, a nie Wewnątrz extern "C"
bloku. Jest to jednak w porządku, ponieważ jeśli ma nie ma prototypu, może być wywoływana tylko przez inne funkcje w tym samym pliku, a potem ogólnie nie obchodzi cię, jak wygląda powiązanie, ponieważ nie planujesz, aby ta funkcja była wywoływana przez cokolwiek poza tą samą jednostką kompilacyjną.
Dla #4, masz to dokładnie. Jeśli dodajesz nagłówek do kodu, który ma podlinkowanie C (takiego jak kod skompilowany przez kompilator C), musisz extern "C"
nagłówek -- w ten sposób będziesz mógł połączyć się z biblioteką. (W przeciwnym razie Twój linker szukałby funkcji o nazwach takich jak _Z1hic
, gdy ty szukałeś void h(int, char)
5: ten rodzaj mieszania jest częstym powodem, aby używać extern "C"
, i nie widzę nic złego w robieniu tego w ten sposób-po prostu upewnij się, że rozumiesz, co robisz.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-09-24 17:32:50
extern "C"
nie zmienia obecności lub braku makra__cplusplus
. To tylko zmienia linkowanie i wymazywanie nazw owiniętych deklaracji.Możesz zagnieżdżać
extern "C"
klocki całkiem szczęśliwie.Jeśli skompilujesz swoje pliki
.c
jako C++, to wszystko, co nie znajduje się w blokuextern "C"
i bez prototypuextern "C"
, będzie traktowane jako funkcja C++. Jeśli skompilujesz je jako C to oczywiście wszystko będzie C funkcja.-
Tak
W ten sposób można bezpiecznie mieszać C i C++.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-11-27 11:02:52
Kilka gotchas, które są kolorami do doskonałej odpowiedzi Andrew Shelansky ' ego i trochę się nie zgodzić z nie zmienia sposobu, w jaki kompilator odczytuje kod
Ponieważ prototypy funkcji są kompilowane jako C, nie można przeciążać tych samych nazw funkcji o różnych parametrach - to jedna z kluczowych cech zniekształcania nazwy kompilatora. Jest to opisane jako problem z połączeniem, ale to nie do końca prawda - otrzymasz błędy z obu kompilator i linker.
Błędy kompilatora pojawią się, jeśli spróbujesz użyć funkcji C++ deklaracji prototypu, takich jak przeciążenie.
Błędy linkera pojawią się później, ponieważ twoja funkcja nie zostanie znaleziona, jeślinie MASZextern "C" Owijacz wokół deklaracji i nagłówek jest zawarty w mieszaninie źródeł C i C++.
Jednym z powodów, aby zniechęcić ludzi do używania kompilacji C jako C++ jest to, że oznacza to, że ich kod źródłowy nie jest już przenośny. To ustawienie jest ustawieniem projektu, a więc jeśli .plik c jest wrzucany do innego projektu, nie zostanie skompilowany jako c++. Wolałbym, żeby ludzie poświęcili czas na zmianę nazwy pliku na .cpp.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-08-26 08:15:16