Czy C jest znacznie szybszy niż C ++ [zamknięty]

83

O ile rozumiem, wszystkie języki skryptowe i podstawowe programy naukowe są zwykle napisane w C; powoduje to, że implementacja jest nieuporządkowana, ale w pewnym sensie bezpośrednio do celu.

Rozumiem, że ci ludzie chcieliby maksymalnie zwiększyć swoją wydajność, ale czy istnieje prawdziwa różnica między używaniem ciągów C i struktur C a używaniem klas C ++; Wydaje się, że C ++ działa w ten sam sposób, poza funkcjami wirtualnymi, przechowuje funkcję klasy raz, a każda instancja tej klasy wywołuje tę jedną funkcję.

Co sprawia, że ​​C jest szybsze i czy jest to zauważalna różnica w projektach takich jak Python lub sqlite, które muszą być najszybsze?

Will03uk
źródło
9
„Powinieneś zadawać tylko praktyczne pytania, na które można odpowiedzieć na podstawie rzeczywistych problemów, z którymi się borykasz”. - Często zadawane pytania dotyczące stackoverflow.
RedGrittyBrick
2
„Dobrze napisany kod w dowolnym języku jest zawsze lepszy niż słabo napisany kod w jakimkolwiek innym języku”.
Kerrek SB,
5
@Will - Nie. „Czy język jest szybszy niż inny język” jest bez odpowiedzi. Języki nie są szybkie, tylko ich implementacje. „Czy implementacja języka X jest szybsza niż implementacja języka Y w innym?” podlega profilowaniu, ale co profilujesz? Implementacje języków mogą być szybkie lub powolne w różnych obszarach, a przetestowanie wszystkich z nich jest niewątpliwie niemożliwe. Lepszym pytaniem byłoby „Dlaczego projektanci języków wybierają język X zamiast języka Y?” To ma jasną odpowiedź (uzasadnienia podane przez różnych projektantów języków) i jest bardziej prawdopodobne, że będzie pomocne.
Chris Lutz,
3
Ten sam kod w C i C ++ powinien zwykle działać z dokładnie taką samą szybkością, z wyjątkiem kodu, który ma inną semantykę z powodu różnych reguł aliasingu itp. Różnica jest między idiomami C i C ++. Jeśli piszesz kod z najlepszymi praktykami idiomami C w C lub C ++, będzie on zwykle znacznie lżejszy i szybszy (i będzie miał mniej przypadków błędów do obsłużenia) niż podobna funkcjonalność napisana za pomocą idiomów C ++ najlepszych praktyk (niezależnie od tego, czy ją piszesz w C lub C ++), ale napisanie prawdopodobnie zajmie ci dużo więcej pracy.
R .. GitHub PRZESTAŃ POMÓC W LODZIE
9
C jest znacznie szybszy do nauczenia się w całości niż C ++;)
fredoverflow

Odpowiedzi:

68

C ++ jest często używany w programach naukowych. Popularność języka C może słabnąć w tej domenie. Fortran pozostaje popularny jako język „niskiego poziomu”.

W C ++ „płacisz tylko za to, czego używasz”. Nie ma więc nic, co spowalniałoby go wolniej niż C. W szczególności w przypadku programów naukowych szablony wyrażeń umożliwiają wykonanie pewnej niestandardowej optymalizacji przy użyciu silnika szablonów do przetwarzania semantyki programu.

Powodem, dla którego język C jest preferowany w projektach takich jak Python, jest to, że czytanie jest mniej zagmatwane, więc duża baza kodu będzie bardziej dostępna dla większej puli współpracowników.

SQLite wymaga małego rozmiaru kodu wykonywalnego, gdzie C ma niewielką przewagę. Rozsądne użycie C ++ nadal pozwala na użycie w aplikacjach wbudowanych, ale jest mniej popularne ze względu na obawy, że wkradną się niechciane funkcje językowe.

Potatoswatter
źródło
10
Zwróć uwagę, że C ++ ma nazwę mangling, podczas gdy C nie, to ułatwia innym językom bezpośrednią współpracę z C. (W rzeczywistości swig buduje interfejs C do kodu C ++ przed utworzeniem opakowania Pythona do biblioteki C ++.)
Sam P
8
@SamP C ++ posiada funkcję wyłączyć przekręcona nazwa, extern "C". Swig używa C jako lingua franca, ale możesz zaimplementować to opakowanie w podzbiorze C ++ zgodnym z C i nigdy nie wywoływać kompilatora C.
Potatoswatter
„SQLite wymaga małego rozmiaru kodu wykonywalnego, gdzie C ma niewielką przewagę”. Nie sądzę, żeby SQLite napisane w idiomatycznym C ++ było większe binarnie lub wolniejsze niż implementacja w C. Z pewnością byłoby o wiele mniej kodu w C ++ i mogłoby oferować opcjonalne LINQ i wstępne optymalizowanie i kompilację zapytań w czasie kompilacji. C wymagałoby do tego generatora kodu, a zatem z SQLITE nie można wstępnie kompilować zapytań. C ++ SQLITE pozwoliłby ci na iterację rekordów z zakresem bez żadnego kodu maszyny wirtualnej, co sprawiłoby, że C SQLITE w porównaniu z nim wydawałby się ślimakowy. Szkoda ...
Kuba nie zapomniał o Monice
W rzeczywistości typowa osadzona aplikacja SQLITE uwzględniająca rozmiar ma ustalony zestaw zapytań, a baza danych jest mapowana w pamięci z pamięci flash, ze stałym schematem, a interpreter SQL i maszyna wirtualna są martwe, podobnie jak wiele innych kodów. Zrobiłem kilka eksperymentów z pisaniem zapytań w „surowym” C, używając dostępu do stron na niskim poziomie w SQLITE i dla mojej konkretnej aplikacji mogłem odrzucić mniej więcej 85% kodu SQLITE. Tak więc, jeśli już, SQLITE traci dużo czasu, nie wykorzystując C ++, ale jest skierowany do platform, na których nie jest dostępny C ++, i nie zaimplementowali generatora kodu C dla zapytań.
Kuba nie zapomniał o Monice
@UnslanderMonica 1. Pliki binarne C ++ mają tabele obsługi wyjątków, które dodają margines nawet wtedy, gdy są puste. 2. SQLite jest oparty na kodzie bajtowym. Optymalizacja zapytań w czasie kompilacji w C ++ oznaczałaby parsowanie i analizę w funkcjach constexpr, które nie mogą używać wskaźników. To sugeruje zmiany architektoniczne, takie, że produkt nie będzie już SQLite. 3. Czy nie ma sposobu na zapisanie kodu bajtowego i usunięcie tekstu i parsera z plików binarnych aplikacji i biblioteki? 4. Wolny od parsera lub „bezgłowy” SQLite może łączyć się z generatorem / optymalizatorem kodu bajtowego C ++ tylko z nagłówkiem.
Potatoswatter
27

Nie sądzę, aby powód był tak bardzo związany z wydajnością, jak z interoperacyjnością. Język C ++ jest bardziej złożony niż język C, ale z punktu widzenia wydajności nie powinno być zauważalnych różnic w obu przypadkach. Niektóre konstrukcje C ++ są szybsze niż ich odpowiedniki w C ( std::sortsą szybsze niż qsort) i prawdopodobnie istnieją dobre przykłady odwrotnej sytuacji.

EDYCJA: Po stronie interoperacyjności ...

Zasadniczo standard C ++ nie definiuje niektórych rzeczy, które mogą być potrzebne do łatwego współdziałania między plikami binarnymi utworzonymi za pomocą różnych kompilatorów / wersji. Najbardziej zauważalną kwestią byłaby konwencja nazewnictwa symboli w systemie binarnym. W języku C język definiuje pojedyncze mapowanie z każdego symbolu w kodzie na nazwę symbolu binarnego. Wywołana funkcja my_functionutworzy symbol w wywołanym pliku binarnym my_function. Z drugiej strony, ze względu na cechy takie jak przeciążanie funkcji, nazwy funkcji C ++ muszą zostać zniekształcone(przetłumaczone na różne symbole funkcji w pliku binarnym, kodujące typy argumentów i typy zwracane), a standard nie definiuje, w jaki sposób odbywa się zniekształcanie. To z kolei oznacza, że ​​ta sama funkcja w C ++ może być skompilowana do różnych symboli w zależności od kompilatora (chyba że extern "C"jest używana do wymuszenia współdziałania C dla tych funkcji w C ++).

Pod koniec dnia interfejs między językiem skryptowym a rodzimym kodem i tak musiałby być interfejsem C, nawet jeśli szczegóły dotyczące jego wewnętrznej implementacji mogłyby być C / C ++ / jakimkolwiek innym językiem ojczystym.

(Celowo nie chcę wdawać się w płomienną wojnę o preferencje językowe, C ++ jest naprawdę potężny, ale jest też trochę przerażający, ponieważ jest znacznie bardziej złożonym językiem niż C, a niektóre rzeczy, które wyglądają na proste, mogą mieć wpływ na wydajność)

David Rodríguez - dribeas
źródło
2
Myślę, że można śmiało powiedzieć, że nowoczesny, idiomatyczny C ++ wymaga inteligentnego kompilatora, aby w pełni wykorzystać zalety inliningu, RVO, stałego składania itp. Dzięki temu jest całkowicie możliwe, że ciężkie konstrukcje C ++ nie są w ogóle zauważalne w poziom maszyny, ale dobry kompilator jest o wiele ważniejszy dla C ++ niż dla C.
Kerrek SB
@Kerrek SB: Większość nowoczesnych kompilatorów C ++ (gdzie współczesne oznacza ostatnie kilka lat) jest naprawdę dobra w identyfikowaniu idiomatycznych konstrukcji C ++ i optymalizacji. Oto std::sortjeden z takich przykładów: std::lessfunktor używany domyślnie nie jest mniej wydajny niż równoważna funkcja w C, ale wszystkie znane mi kompilatory wbudują go (jako szablon jest dostępny do wstawiania) i usuwają wszystkie wywołania funkcji do comparefunktora.
David Rodríguez - dribeas
Co zabawne, biblioteka EASTL firmy Electronic Arts jest częściowo uzasadniona twierdzeniem, że uznali GCC za słabe w inliningu (a MSVC za znacznie lepsze), a zatem biblioteka standardowa spowodowałaby zbyt wiele niezoptymalizowanych wywołań funkcji. W EASTL używają mniej pośredników, aby temu przeciwdziałać. Kto wie, jak dobrze to rozumowanie sprawdza się obecnie.
Kerrek SB,
13

Jak Bjarne wspomniał w [D&E], efektywność jest jednym z głównych celów C ++. Więc C ++ jest wolniejszy tylko wtedy, gdy programista używa swoich "dodatkowych" funkcji, takich jak funkcje wirtualne, o których wspomniałeś, informacje rtt itp

Myślę więc, że jest to bardziej z powodów psychologicznych - używane jest C, ponieważ nie pozwala na "powolne" funkcje C ++.

przechytrzyć
źródło
9

Języki nie są z natury szybsze ani wolniejsze, interpretery i kompilatory mogą być mniej lub bardziej wydajne.

Poza tym języki wyższego poziomu zapewniają warstwy abstrakcji, które zwykle wiążą się z kosztami czasu wykonania. Jeśli ich nie używasz, kompilator może być wystarczająco sprytny, aby je usunąć, ale może to nie być możliwe, jeśli semantyka języka nie pozwala na to bezpiecznie ... A jeśli ich potrzebujesz, zaimplementuj je samodzielnie w przypadku języka niższego poziomu będzie prawdopodobnie wolniejsze niż używanie języka „wolnego”.

fortran
źródło
25
Języki skryptowe są dziedziczone wolniej niż kompilowane, chyba że napiszesz naprawdę okropnie skompilowany kod
Will03uk
2
@ Will03uk - Co powstrzymuje Cię przed napisaniem kompilatora dla języka skryptowego?
Chris Lutz,
6
@Chris to nie byłby język skryptowy; konsekwencją języka skryptowego jest to, że jest on interpretowany lub skompilowany kod bajtowy. Kiedy już go skompilujesz, czy nie jest to język skompilowany
Will03uk
1
to nie jest cała prawda: semantyka języka ma znaczenie, ponieważ determinuje informacje dostępne optymalizatorowi i jakie założenia można bezpiecznie przyjąć bez konieczności przeprowadzania analizy całego programu; restrictPrzykład : słowo kluczowe w C lub luajit - to ostatnie nie wysadza z wody co drugi vm dla języków dynamicznych tylko dlatego, że Mike jest sprytnym facetem, ale także dlatego, że semantyka Lua jest dość przejrzysta (w porównaniu np. z JavaScriptem)
Christoph,
1
@Christoph Próbuję powiedzieć, że nie ma srebrnej kuli. Jeśli potrzebujesz takich rzeczy, jak dynamiczne wysyłanie, wirtualne wywołania, gorące ładowanie kodu lub pisanie na klawiaturze, język, który może wydawać się „wolny” po wyjęciu z pudełka, jest prawdopodobnie szybszy niż naiwna implementacja w C.
fortran