Многие из этих ответов дают веские причины того, почему C быстрее или нет (в целом или в определенных сценариях). Это бесспорно, что:
- Многие другие языки предоставляют автоматические функции, которые мы считаем само собой разумеющимся. Например, проверка границ, проверка типов во время выполнения и автоматическое управление памятью бесплатны. С этими функциями связана, по крайней мере, некоторая стоимость, о которой мы можем не думать - или даже не осознавать - при написании кода, использующего эти функции.
- Шаг от источника к машине часто не такой прямой на других языках, как на C.
- OTOH, сказать, что скомпилированный код C выполняется быстрее, чем другой код, написанный на других языках, является обобщением, которое не всегда верно. Контрпримеры легко найти (или придумать).
Несмотря на все это, есть кое-что еще, что я заметил, что, как мне кажется, влияет на сравнительную производительность языка C по сравнению со многими другими языками в большей степени, чем любой другой фактор. Для остроумия:
Другие языки часто облегчают написание кода, который выполняется медленнее. Часто это даже поощряется философией дизайна языка. Следствие: программист на C с большей вероятностью будет писать код, который не выполняет ненужных операций.
В качестве примера рассмотрим простую программу Windows, в которой создается одно главное окно. Версия AC будет заполнять WNDCLASS[EX]структуру, которая будет передана RegisterClass[Ex], затем вызывать CreateWindow[Ex]и вводить цикл сообщений. Ниже приведен очень упрощенный и сокращенный код:
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);
}
Эквивалентная программа на C # может быть всего одной строкой кода:
Application.Run(new Form());
Эта единственная строка кода предоставляет все функциональные возможности, которые сделали почти 20 строк кода на C, и добавляет некоторые вещи, которые мы пропустили, такие как проверка ошибок. Более богатая и полная библиотека (по сравнению с библиотеками, используемыми в типичном C-проекте) проделала большую работу для нас, освободив наше время для написания еще большего количества фрагментов кода, которые нам не хватает, но требуют много шагов за кулисами.
Но богатая библиотека, обеспечивающая легкое и быстрое раздувание кода, на самом деле не моя точка зрения. Моя точка зрения становится более очевидной, когда вы начинаете изучать, что на самом деле происходит, когда наша маленькая однострочная строка действительно выполняется. Для развлечения иногда включите доступ к исходным кодам .NET в Visual Studio 2008 или более поздней версии и перейдите к простой строчке выше. Одна из забавных маленьких жемчужин, с которыми вы столкнетесь, - это комментарий в получателе 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();
}
Десять раз . Информация, приблизительно эквивалентная сумме того, что хранится в WNDCLASSEXструктуре и того, что передано, CreateWindowExизвлекается из Controlкласса десять раз, прежде чем она сохраняется в WNDCLASSEXструктуре и передается в RegisterClassExи CreateWindowEx.
В общем, количество инструкций, выполняемых для выполнения этой основной задачи, на 2–3 порядка больше в C #, чем в C. Отчасти это связано с использованием многофункциональной библиотеки, которая обязательно обобщается по сравнению с наш простой C-код, который делает именно то, что нам нужно, и ничего более. Но отчасти это связано с тем, что модульная, объектно-ориентированная природа .NET Framework поддается многократному повторению выполнения, которого часто избегает процедурный подход.
Я не пытаюсь выбрать на C # или .NET Framework. Также я не говорю, что модульность, обобщение, функции библиотеки / языка, ООП и т. Д. - это плохие вещи . Я делал большую часть своей разработки на C, позже на C ++, а в последнее время на C #. Точно так же до C я использовал в основном сборку. И с каждым шагом "выше" мой язык, я пишу лучше, более удобные в обслуживании, более надежные программы за меньшее время. Они, однако, имеют тенденцию исполняться немного медленнее.