Po co nam extern"C" {#include} W C++? [duplikat]
To pytanie ma już odpowiedź tutaj:
- jaki jest efekt extern " C " w C++? 13 Odpowiedzi
Dlaczego musimy używać:
extern "C" {
#include <foo.h>
}
Konkretnie:
Kiedy powinniśmy go użyć?
Co dzieje się na poziomie kompilatora/linkera, który wymaga od nas jego użycia?
Jak w kategoriach kompilacji / linkowania czy to rozwiązuje problemy, które wymagają od nas jej użycia?
10 answers
C i C++ są powierzchownie podobne, ale każdy kompiluje się w zupełnie inny zestaw kodu. Gdy dołączasz plik nagłówkowy do kompilatora C++, kompilator oczekuje kodu C++. Jeśli jednak jest to nagłówek C, kompilator oczekuje, że dane zawarte w pliku nagłówkowym zostaną skompilowane do określonego formatu-C++ 'ABI', lub 'Application Binary Interface' , więc linker się dusi. Jest to lepsze od przekazywania danych C++ do funkcji oczekującej danych C.
(aby dostać się do naprawdę w C++, ABI Zwykle 'manipuluje' nazwami swoich funkcji/metod, więc wywołanie printf()
bez oznaczania prototypu jako funkcji C, C++ wygeneruje wywołanie kodu _Zprintf
, plus dodatkowe bzdury na końcu.)
Tak więc: użyj extern "C" {...};
, gdy dodasz nagłówek c-to takie proste. W przeciwnym razie będziesz miał niedopasowanie w skompilowanym kodzie, a linker się udusi. Jednak w przypadku większości nagłówków nie będziesz nawet potrzebował extern
, ponieważ większość nagłówków systemu c już uwzględnia fakt że mogą być zawarte w kodzie C++ i już extern
ich kod.
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-10-15 00:20:08
Extern " C " określa, jak symbole w wygenerowanym pliku obiektowym mają być nazwane. Jeśli funkcja jest zadeklarowana bez extern "C", Nazwa symbolu w pliku obiektowym będzie używać C++ name mangling. Oto przykład.
Podany test.C jak tak:
void foo() { }
Kompilacja i lista symboli w pliku obiektowym daje:
$ g++ -c test.C
$ nm test.o
0000000000000000 T _Z3foov
U __gxx_personality_v0
Funkcja foo w rzeczywistości nazywa się "_Z3foov". Łańcuch ten zawiera między innymi informacje o typie zwracanego typu i parametrach. Jeśli zamiast tego napisz test.C jak to:
extern "C" {
void foo() { }
}
Następnie skompiluj i spójrz na symbole:
$ g++ -c test.C
$ nm test.o
U __gxx_personality_v0
0000000000000000 T foo
Dostajesz połączenie C. Nazwa funkcji " foo "w pliku obiektowym to po prostu" foo " i nie ma ona wszystkich fantazyjnych informacji o typie, które pochodzą z namaglowania nazwy.
Zazwyczaj dołączasz nagłówek w extern " C " {} jeśli kod, który się z nim wiąże, został skompilowany za pomocą kompilatora C, ale próbujesz go wywołać z C++. Kiedy to robisz, mówisz kompilatorowi, że wszystkie deklaracje w nagłówku użyje linkowania C. Kiedy połączysz swój kod, Twój .o pliki będą zawierać odniesienia do "foo", a nie" _Z3fooblah", które, miejmy nadzieję, pasują do tego, co jest w bibliotece, z którą linkujesz.
Większość nowoczesnych bibliotek będzie umieszczać osłony wokół takich nagłówków, tak aby symbole były deklarowane z odpowiednim połączeniem. np. w wielu standardowych nagłówkach znajdziesz:
#ifdef __cplusplus
extern "C" {
#endif
... declarations ...
#ifdef __cplusplus
}
#endif
To sprawia, że gdy kod C++ zawiera nagłówek, symbole w pliku obiektowym pasują do tego, co jest w biblioteka C. Powinieneś tylko umieścić extern " C " {} wokół nagłówka C, jeśli jest stary i nie ma już tych strażników.
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
2008-09-16 00:07:06
W C++ możesz mieć różne encje, które mają wspólną nazwę. Na przykład poniżej znajduje się lista funkcji o nazwie foo :
A::foo()
B::foo()
C::foo(int)
C::foo(std::string)
W celu odróżnienia ich wszystkich, kompilator C++ utworzy unikalne nazwy dla każdego z nich w procesie zwanym namaszczaniem nazw lub dekorowaniem. Kompilatory C tego nie robią. Co więcej, każdy kompilator C++ może to zrobić w inny sposób.
Extern" C " mówi C++ kompilator nie wykonuje żadnych namagnesowań nazw na kodzie w nawiasach klamrowych. Pozwala to na wywołanie funkcji C z poziomu 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
2017-10-05 07:35:46
Ma to związek ze sposobem, w jaki różne Kompilatory wykonują manipulowanie nazwami. Kompilator C++ zmieni nazwę symbolu wyeksportowanego z pliku nagłówkowego w zupełnie inny sposób niż kompilator C, więc gdy spróbujesz połączyć, pojawi się błąd linkera mówiący o brakujących symbolach.
Aby rozwiązać ten problem, mówimy kompilatorowi C++, aby działał w trybie "C", więc wykonuje on manipulowanie nazw w taki sam sposób, jak kompilator C. Po wykonaniu tego zadania Naprawiono błędy linkera.
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
2008-09-15 23:24:32
Kiedy powinniśmy go użyć?
Podczas łączenia bibliotek C w pliki obiektowe C++
Co się dzieje w poziom kompilatora / linkera, który wymaga od nas żeby go użyć?
C i C++ używają różnych schematów nazewnictwa symboli. To mówi linkerowi, aby używał schematu C podczas linkowania w danej bibliotece.
Jak pod względem kompilacji / linkowania czy to rozwiązuje problemy, które chcesz, żebyśmy go użyli?
Używanie C schemat nazewnictwa pozwala odwoływać się do symboli w stylu C. W przeciwnym razie linker spróbowałby użyć symboli w stylu C++, które nie zadziałałyby.
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
2008-09-15 23:29:41
C i C++ mają różne zasady dotyczące nazw symboli. Dzięki symbolom linker wie, że wywołanie funkcji " openBankAccount "w jednym pliku obiektowym wyprodukowanym przez kompilator jest odniesieniem do funkcji, którą nazwałeś" openBankAccount " w innym pliku obiektowym wyprodukowanym z innego pliku źródłowego przez ten sam (lub kompatybilny) kompilator. Pozwala to na wykonanie programu z więcej niż jednego pliku źródłowego, co jest ulgą podczas pracy nad dużym projektem.
W C reguła jest bardzo proste, symbole i tak są w jednej przestrzeni nazw. Tak więc liczba całkowita "socks" jest przechowywana jako "socks", a funkcja count_socks jest przechowywana jako "count_socks".
Linkery zostały zbudowane dla języka C i innych języków, takich jak C, z tą prostą regułą nazewnictwa symboli. Tak więc symbole w linkerze są tylko prostymi łańcuchami.
Ale w C++ język pozwala mieć przestrzenie nazw, polimorfizm i różne inne rzeczy, które są sprzeczne z tak prostą regułą. Wszystkie sześć funkcji polimorficznych o nazwie " dodaj" trzeba mieć różne symbole, albo niewłaściwy będzie używany przez inne pliki obiektowe. Odbywa się to poprzez "zniekształcanie" (to termin techniczny) nazw symboli.
Podczas łączenia kodu C++ z bibliotekami lub kodem C, potrzebujesz extern" C " cokolwiek napisanego w C, takie jak pliki nagłówkowe dla bibliotek C, aby powiedzieć kompilatorowi C++, że te nazwy symboli nie mogą być zniekształcone, podczas gdy reszta kodu C++ Oczywiście musi być zniekształcona lub nie będzie działać.
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
2008-09-15 23:28:54
Powinieneś używać extern " C " za każdym razem, gdy dołączasz nagłówek definiujący funkcje znajdujące się w pliku skompilowanym przez kompilator C, używanym w pliku C++. (Wiele standardowych bibliotek C może zawierać tę kontrolę w swoich nagłówkach, aby ułatwić programistom)
Na przykład, jeśli masz projekt z 3 plikami, util.c, util.h I main.cpp i obie .c i .pliki cpp są kompilowane za pomocą kompilatora C++ (g++, cc, itp.), a następnie nie jest to naprawdę potrzebne, a nawet może powodować błędy linkera. Jeśli proces budowania wykorzystuje zwykły kompilator C dla util.c, wtedy będziesz musiał użyć extern "C", gdy włączysz util.h.
Dzieje się tak, że C++ koduje parametry funkcji w jej nazwie. Tak działa przeciążenie funkcji. Wszystko, co zwykle zdarza się funkcji C, to dodanie podkreślenia ("_") na początku nazwy. Bez użycia extern " C " linker będzie szukał funkcji o nazwie DoSomething@ @ int@float (), gdy rzeczywista nazwa funkcji to _dosomething () lub po prostu Dosometh ().
Użycie extern " C " rozwiązuje powyższy problem, mówiąc kompilatorowi C++, że powinien szukać funkcji zgodnej z konwencją nazewnictwa C zamiast 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
2008-09-15 23:45:40
Konstrukt extern "C" {}
nakazuje kompilatorowi nie wykonywać manglowania na nazwach zadeklarowanych w nawiasach klamrowych. Zwykle kompilator C++ "rozszerza" nazwy funkcji tak, że koduje informacje o argumentach i zwracanej wartości; nazywa się to zniekształconą nazwą. Konstrukcja extern "C"
zapobiega maglowaniu.
Jest zwykle używany, gdy kod C++ musi wywołać bibliotekę języka C. Może być również używany podczas wystawiania funkcji C++ (na przykład z DLL) Na C klientów.
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
2008-09-15 23:30:25
Kompilator C++ tworzy nazwy symboli inaczej niż kompilator C. Tak więc, jeśli próbujesz wywołać funkcję znajdującą się w pliku C, skompilowanym jako kod C, musisz powiedzieć kompilatorowi C++, że nazwy symboli, które próbuje rozwiązać, wyglądają inaczej niż domyślnie; w przeciwnym razie krok łącza się nie powiedzie.
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
2008-09-16 02:07:52
Służy do rozwiązywania problemów z manipulowaniem nazwami. extern C oznacza, że funkcje są w "płaskim" API w stylu 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
2008-09-15 23:25:09