Wiele z tych odpowiedzi podaje uzasadnione powody, dla których C jest lub nie jest szybsze (ogólnie lub w określonych scenariuszach). Jest niezaprzeczalne, że:
- Wiele innych języków zapewnia automatyczne funkcje, które uważamy za oczywiste. Na przykład sprawdzanie granic, sprawdzanie typu w czasie wykonywania i automatyczne zarządzanie pamięcią nie są darmowe. Z tymi funkcjami wiążą się co najmniej pewne koszty, o których nie możemy myśleć ani nawet nie zdawać sobie sprawy podczas pisania kodu, który korzysta z tych funkcji.
- Krok od źródła do maszyny często nie jest tak bezpośredni w innych językach, jak w C.
- OTOH, powiedzenie, że skompilowany kod C działa szybciej niż inny kod napisany w innych językach, jest uogólnieniem, które nie zawsze jest prawdziwe. Kontrprzykłady można łatwo znaleźć (lub wymyślić).
Mimo to, zauważyłem coś jeszcze, co, jak sądzę, wpływa bardziej na porównawczą wydajność C w porównaniu do wielu innych języków bardziej niż jakikolwiek inny czynnik. To znaczy:
Inne języki często ułatwiają pisanie kodu, który działa wolniej. Często jest to wspierane przez filozofie projektowania języka. Następstwo: programiści C częściej piszą kod, który nie wykonuje niepotrzebnych operacji.
Jako przykład rozważ prosty program Windows, w którym tworzone jest pojedyncze okno główne. Wersja AC wypełniłaby WNDCLASS[EX]
strukturę, która byłaby przekazana RegisterClass[Ex]
, a następnie wywołała CreateWindow[Ex]
i wprowadziła pętlę komunikatów. Wysoce uproszczony i skrócony kod wygląda następująco:
WNDCLASS wc;
MSG msg;
wc.style = 0;
wc.lpfnWndProc = &WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = NULL;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
wc.lpszMenuName = NULL;
wc.lpszClassName = "MainWndCls";
RegisterClass(&wc);
CreateWindow("MainWndCls", "", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
while(GetMessage(&msg, NULL, 0, 0)){
TranslateMessage(&msg);
DispatchMessage(&msg);
}
Odpowiednikiem programu w języku C # może być tylko jeden wiersz kodu:
Application.Run(new Form());
Ten jeden wiersz kodu zapewnia wszystkie funkcje, które zrobiło prawie 20 wierszy kodu C, i dodaje pewne rzeczy, które pominęliśmy, takie jak sprawdzanie błędów. Bogatsza, pełniejsza biblioteka (w porównaniu do tych używanych w typowym projekcie C) wykonała dla nas dużo pracy, uwalniając nasz czas na pisanie wielu fragmentów kodu, które są dla nas krótkie, ale wymagają wielu kroków za kulisami.
Ale bogata biblioteka umożliwiająca łatwe i szybkie rozszerzanie kodu nie jest moim celem. Moja uwaga jest bardziej widoczna, gdy zaczynasz badać, co faktycznie dzieje się, gdy nasz mały liniowiec faktycznie wykonuje. Czasami dla zabawy włącz dostęp do źródła .NET w Visual Studio 2008 lub nowszym i przejdź do prostej linijki powyżej. Jednym z zabawnych małych klejnotów, które można napotkać, jest ten komentarz na forum dla Control.CreateParams
:
// In a typical control this is accessed ten times to create and show a control.
// It is a net memory savings, then, to maintain a copy on control.
//
if (createParams == null) {
createParams = new CreateParams();
}
Dziesięć razy . Informacje w przybliżeniu równoważne sumie tego, co jest przechowywane w WNDCLASSEX
strukturze i tego, co jest przekazywane, CreateWindowEx
jest pobierane z Control
klasy dziesięć razy, zanim zostanie zapisane w WNDCLASSEX
strukturze i przekazane do RegisterClassEx
i CreateWindowEx
.
Podsumowując, liczba instrukcji wykonanych w celu wykonania tego bardzo podstawowego zadania wynosi 2–3 rzędy wielkości więcej w C # niż w C. Część tego wynika z użycia bogatej w funkcje biblioteki, która jest koniecznie uogólniona, w porównaniu z nasz prosty kod C, który robi dokładnie to, czego potrzebujemy i nic więcej. Ale częściowo wynika to z faktu, że modularna, zorientowana obiektowo natura frameworku .NET pozwala na wiele powtórzeń wykonywania, których często można uniknąć dzięki podejściu proceduralnemu.
Nie próbuję wybrać C # lub .NET. Nie mówię też, że modularyzacja, uogólnienie, funkcje biblioteki / języka, OOP itp. Są złymi rzeczami . Zwykle zajmowałem się głównie programowaniem w C, później w C ++, a ostatnio w C #. Podobnie przed C korzystałem głównie z montażu. I z każdym krokiem „wyżej” idzie mój język, piszę lepsze, łatwiejsze w utrzymaniu, bardziej niezawodne programy w krótszym czasie. Z reguły jednak wykonują się nieco wolniej.