Ostatnio zastanawiałem się, kiedy używać C zamiast C ++ i vice versa? Na szczęście ktoś już mnie pobił i chociaż zajęło mi to trochę czasu, byłem w stanie przetrawić wszystkie odpowiedzi i komentarze do tego pytania.
Jednak jeden element w tym poście jest ciągle adresowany bez żadnego przykładu, weryfikacji lub wyjaśnienia:
„Kod C jest przydatny, gdy chcesz mieć wiele powiązań językowych dla swojej biblioteki”
To parafraza. Powinienem zauważyć, że kilka osób wskazuje, że w C ++ możliwe jest wiele powiązań językowych (za pośrednictwem niektórych extern
funkcji), ale mimo to, jeśli czytasz ten post w całości, oczywiste jest, że C jest idealny do przenoszenia / wiązania językowego. Moje pytanie brzmi: dlaczego?
Czy ktoś może podać konkretne powody, dla których pisanie bibliotek w C pozwala na łatwiejsze powiązania i / lub przenośność w innych językach?
Odpowiedzi:
C ma znacznie, znacznie prostszy interfejs, a jego zasady przekształcania interfejsu kodu źródłowego w interfejs binarny są na tyle proste, że generowanie zewnętrznych interfejsów do wiązania odbywa się w dobrze ustalony sposób. Z drugiej strony C ++ ma niezwykle skomplikowany interfejs, a zasady wiązania ABI nie są w ogóle standaryzowane, ani formalnie, ani w praktyce. Oznacza to, że prawie każdy kompilator dla dowolnego języka dla dowolnej platformy może powiązać się z zewnętrznym interfejsem C i dokładnie wiedzieć, czego się spodziewać, ale dla interfejsu C ++ jest to zasadniczo niemożliwe, ponieważ reguły zmieniają się w zależności od tego, który kompilator, która wersja i który platforma, na której zbudowano kod C ++.
źródło
extern "C"
jest jeszcze więcej dodatkowych prac, które należy zrównoważyć z funkcjami dostarczonymi przez C ++)extern "C"
.Jeśli próbujesz komunikować się z mówcą w innym języku, pidgin jest łatwiejszy niż szekspirowski angielski.
Pojęcia C - wywołania funkcji, wskaźniki, ciągi zakończone znakiem NULL - są bardzo proste, więc inne języki mogą łatwo je zaimplementować wystarczająco dobrze, aby wywoływać funkcje C. Ze względów historycznych wiele innych języków jest zaimplementowanych w C, co jeszcze bardziej ułatwia wywoływanie funkcji C.
C ++ dodaje całkiem sporo rzeczy - klas, z dziedziczeniem i vtables oraz modyfikatorami dostępu; wyjątki, z rozwijaniem stosu i zmienianiem przepływu kontroli; szablony. Wszystko to utrudnia innym językom korzystanie z powiązań C ++: w najlepszym przypadku jest więcej „kleju” lub kodu interoperacyjności do wdrożenia, aw najgorszym przypadku koncepcje nie tłumaczą bezpośrednio (z powodu różnic w modelach klas, obsłudze wyjątków, itp.). W szczególności w przypadku szablonów po prostu ich użycie (utworzenie wystąpienia) zazwyczaj wymaga etapu kompilacji za pomocą kompilatora C ++, co znacznie komplikuje korzystanie z nich z innych środowisk.
Biorąc to wszystko pod uwagę, można przecenić trudność w udostępnianiu powiązań z biblioteki C ++ do innego języka:
extern "C"
, więc możesz eksportować powiązania językowe w stylu C (z całą prostotą i kompatybilnością powiązań C) z biblioteki C ++ (z tym, że nie możesz ujawnić żadnej funkcji specyficznej dla C ++) .źródło
C jest jednym z najstarszych wciąż istniejących języków. Jego ABI jest prosty i napisano w nim praktycznie każdy wciąż używany system operacyjny . Podczas gdy niektóre z tych systemów operacyjnych mogły dodawać elementy, np. W C # / .NET lub cokolwiek na górze, poniżej są bardzo mocno zanurzone w C.
Oznacza to, że w celu wykorzystania możliwości oferowanych przez system operacyjny, praktycznie każdy język programowania tam potrzebne drogę do współpracy z bibliotekami C w każdym razie . Perl, Java, C ++, wszyscy natywnie zapewniają sposoby „mówienia w C”, ponieważ musieli, jeśli nie chcieli wymyślać każdego koła z osobna.
To sprawia, że C jest łaciną języków programowania. (Ile lat internetu przed tą metaforą musi być „angielski języków programowania”?)
Kiedy piszesz swoją bibliotekę w C, dostajesz interfejs kompatybilny z C za darmo (oczywiście). Jeśli piszesz biblioteki w C ++, to może dostać wiązań C, poprzez
extern "C"
deklaracje jak wspomniano.Jednakże , można dostać te wiązania tylko na funkcjonalność , która może być wyrażona w ° C .
Dlatego interfejs API Twojej biblioteki nie może korzystać z ...
Jednym prostym przykładem byłoby zmuszenie eksportowanych funkcji do przyjmowania i zwracania tablic (
[]
) zamiaststd::vector
(lubstd::string
w tym przypadku).Zatem nie tylko nie byłbyś w stanie zapewnić żadnej z dobrych rzeczy, które C ++ ma do zaoferowania klientom biblioteki, ale musiałbyś również podjąć dodatkowe wysiłki, aby „przetłumaczyć” swój interfejs API biblioteki z C ++ na „kompatybilny z C” (
extern "C"
).Dlatego można stwierdzić, że C jest lepszym wyborem do implementacji biblioteki. Osobiście uważam, że zalety C ++ wciąż przewyższają konieczny wysiłek związany z
extern "C"
API, ale to tylko ja.źródło
Pozostawiając szczegóły inne odpowiedzi już zapewniają:
Powodem, dla którego tak wiele języków udostępnia wiązanie C, jest to, że wszystkie systemy operacyjne * nix i Windows udostępniają większość swojego interfejsu API systemu operacyjnego za pośrednictwem interfejsu C. W związku z tym implementacja języka musi już współpracować z C, aby móc działać na głównych Oses. Dlatego łatwo jest również zaoferować bezpośrednią komunikację z dowolnym interfejsem C z samego języka.
źródło
Nie ma powodu. Jeśli semantyka, którą próbujesz wyrazić, jest zasadniczo zgodna z językiem C, a nie czymś podobnym do szablonów, nie ma powodu, aby łatwiej wiązać, jeśli implementacja jest napisana w języku C. W rzeczywistości z definicji interfejs C może być wypełnione przez dowolne wdrożenie, które może spełnić umowę binarną - w tym wdrożenie w innym języku. Istnieją języki inne niż C ++, które mogą implementować umowy binarne C, które mogą działać w ten sposób.
Sprowadza się to do ludzi, którzy nie chcą uczyć się nowych języków lub pomysłów, które mają naprawdę przydatną semantykę lub cechują się desperacką próbą znalezienia jakiegokolwiek powodu, aby pozostać w erze dinozaurów.
źródło
Istnieją dwie główne osie w przypadku interakcji z innym językiem:
C ma przewagę nad C ++ na tych dwóch frontach:
Teraz, dlaczego większość języków ma podobny zestaw pojęć niż C, ponieważ może być albo „prosty”, albo „wcześniejszy”; nie ma to jednak znaczenia, chodzi o to, że tak.
Wręcz przeciwnie, C ++ ma złożone koncepcje, a o ABI decyduje każdy kompilator (choć wiele stosuje Itanimum ABI, z wyjątkiem Windows ...). W rzeczywistości Herb Sutter zaproponował, aby systemy operacyjne naprawiły C ++ ABI (dla poszczególnych systemów operacyjnych) w celu częściowego rozwiązania tego problemu. Należy również zauważyć, że C ++ FFI jest możliwy, D próbuje go 3 .
1 Z wyjątkiem variadics (
...
), nie są one proste2 Czy C ma standardowy ABI?
3 Interfejs D do starszego kodu C ++
źródło
Zasadniczo sprowadza się to do standaryzacji ABI. Chociaż ani C, ani C ++ nie ma znormalizowanego ABI, którego inne języki mogą używać do interfejsu między zapisanymi plikami binarnymi, C stał się de facto standardem, wszyscy o tym wiedzą i wszyscy inni mogą stosować te same, proste zasady, które język ma w odniesieniu do typy i wywołania funkcji.
C ++ może mieć standardowy ABI, ale Stroustrup powiedział, że nie widzi takiej potrzeby. Mówi także, że trudno byłoby uzyskać konsensus od autorów kompilatorów (choć wątpię, że - komitet standardowy C ++ wydałby ABI podobny do istniejących, a autorzy kompilatorów po prostu zmieniliby kolejną wersję swoich kompilatorów, które czasami są niezgodne z plikami binarnymi i tak zbudowane ze starych wersji ich kompilatorów - przypominam sobie, jak ponownie skompilowałem kilka bibliotek z nowym kompilatorem Sun i stwierdziłem, że nie działały one ze starymi)
Zauważysz, że niektóre firmy przeszły na stosowanie standardowego ABI, Microsoft rozpoczął ten proces z COM jeszcze w latach 90., a dziś udoskonalili go do WinRT ABI (nie mylić z innym WinRT, który odnosi się do typu systemu operacyjnego tabeli), który pozwala programom napisanym w C # komunikować się z bibliotekami napisanymi w C lub C ++ (tj. własna warstwa systemu operacyjnego Microsoft jest napisana w C ++, udostępniona za pomocą WinRT i zużywana przez aplikacje C # podczas wywoływania dowolnej procedury wykonawczej systemu operacyjnego)
Nikt nie może nic zrobić, chyba że organ normalizacyjny podejmie kroki i naprawi tę sytuację. Microsoft oczywiście widzi w tym wartość i podjął kroki w celu rozwiązania tej kwestii na swojej platformie.
Tak więc odpowiedź brzmi: C nie zapewnia powiązań językowych. Zdarza się, że nikt ich nie słuchał i nie zużywa.
źródło
Wszystkie odpowiedzi nie odpowiadają prawdziwemu problemowi: kompilacja w C ++ wprowadza „zmianę nazwy”, więc pliki binarne są niezgodne z „prostymi” wywołaniami funkcji.
Wszystkie rzeczy ABI to tylko próba standaryzacji.
Zasadniczo nie ma gwarancji, że można krzyżować funkcje skompilowane z różnymi kompilatorami, nawet jeśli trzymasz się zwykłego C ++. Dawniej było pewne, że są niekompatybilne, ale obecnie wkrada się normalizacja;)
OTOH C został zaprojektowany właśnie z myślą o „montażu na wysokim poziomie” i umożliwieniu wszelkiego rodzaju łatwego łączenia. Nie powinno dziwić, że lepiej nadaje się do sympatii między językami.
Uwaga dodatkowa: oryginalny kompilator C ++ (front) faktycznie stworzył źródło C, które trzeba było skompilować, dokładnie tak jak gcc, który tworzy asembler „pod maską”.
źródło