Какие конкретные примеры существуют, когда знание C делает вас лучшим программистом высокого уровня?

StackOverflow https://stackoverflow.com/questions/2077913

  •  21-09-2019
  •  | 
  •  

Вопрос

Я знаю о существовании такого вопроса, как Вот этот и Вот этот.Позволь мне объяснить.

Афет читает статью Джоэла Вернуться к основам и увидев много подобных вопросов по SO, я начал задаваться вопросом, каковы конкретные примеры ситуаций, когда знание таких вещей, как C, может сделать вас лучшим программистом высокого уровня.

Я хочу знать, много ли таких примеров.Часто ответ на этот вопрос звучит примерно так: «Знание C дает вам лучшее представление о том, что происходит под одеялом." или "Вам нужна прочная основа для вашей программы", и эти ответы не имеют особого значения.Я хочу понять, какие конкретные преимущества вы получите от знания концепций низкого уровня.

Джоэл привел пару примеров:Двоичные базы данных против XML и строк.Но два примера на самом деле не оправдывают изучение C и/или ассемблера.Итак, мой вопрос заключается в следующем: Какие конкретные примеры существуют, когда знание C делает вас лучшим программистом высокого уровня?

Это было полезно?

Решение

Мой опыт обучения студентов и работы с людьми, которые изучали только языки высокого уровня, показывает, что они склонны мыслить на определенном высоком уровне абстракции и предполагают, что «все дается бесплатно».Они могут стать очень компетентными программистами, но в конечном итоге им приходится иметь дело с кодом, имеющим проблемы с производительностью, и тогда это начинает их кусать.

Когда вы много работаете с C, вы думаете о распределении памяти.Вы часто думаете о структуре памяти (и локальности кэша, если это проблема).Вы понимаете, как и почему некоторые графические операции стоят очень дорого.Насколько эффективны или неэффективны определенные варианты поведения сокетов.Как работают буферы и т.д.Я чувствую, что использование абстракций на языке более высокого уровня, когда вы знаете, как они реализованы под обложками, иногда дает вам «этот дополнительный секретный соус», когда вы думаете о производительности.

Например, в Java есть сборщик мусора, и вы не можете напрямую назначать что-то в память.И тем не менее, вы можете сделать определенные варианты дизайна (например, с помощью пользовательских структур данных), которые повлияют на производительность по тем же причинам, по которым это было бы проблемой в C.

Кроме того, в более общем смысле, я считаю, что для мощного программиста важно не только знать нотацию большого О (которой учат в большинстве школ), но и то, что в реальных приложениях важна также константа (которую школы пытаются игнорировать). .Мой неофициальный опыт показывает, что люди, владеющие обоими языковыми уровнями, обычно лучше понимают константу, возможно, из-за того, что я описал выше.

Кроме того, многие системы более высокого уровня, которые я видел, взаимодействуют с библиотеками и инфраструктурами более низкого уровня.Например, некоторые коммуникации, базы данных или графические библиотеки.Некоторые драйвера для определенных устройств и т.д.Если вы опытный программист, вам, возможно, в конечном итоге придется отправиться туда, и это поможет хотя бы иметь представление о том, что происходит.

Другие советы

Знание вещей низкого уровня может очень помочь.

Чтобы стать автогонщиком, вам необходимо изучить и понять основы физики сцепления шин с дорогой.Любой может научиться водить довольно быстро, но вам нужно хорошее понимание вещей «низкого уровня» (силы и трение, гоночные траектории, точное управление газом и тормозами и т. д.), чтобы получить те последние несколько процентов производительности, которые позволят вам выйграть гонку.

Например, если вы понимаете, как работает архитектура ЦП на вашем компьютере, вы можете написать код, который лучше с ней работает (например,если вы знаете, что у вас есть определенный размер кэша ЦП или определенное количество байтов в каждой строке кэша ЦП, вы можете организовать свои структуры данных и способ доступа к ним так, чтобы максимально эффективно использовать кеш - например, для обработки большого количества элементов упорядочения массива часто происходит быстрее, чем обработка случайных элементов из-за кэша ЦП).Если у вас многоядерный компьютер, то понимание того, как методы низкого уровня, такие как работа с потоками, могут дать огромные преимущества (точно так же, как непонимание низкого уровня может привести к катастрофе в многопоточности).

Если вы понимаете, как работает дисковый ввод-вывод и кэширование, вы можете изменить файловые операции, чтобы они хорошо работали с ним (например.если вы читаете из одного файла и записываете в другой, работа с большими пакетами данных в оперативной памяти может помочь уменьшить конфликты ввода-вывода между этапами чтения и записи вашего кода и значительно повысить пропускную способность)

Если вы понимаете, как работают виртуальные функции, вы можете создавать высокоуровневый код, использующий виртуальные функции. хорошо.При неправильном использовании они могут серьезно ухудшить производительность.

Если вы понимаете, как происходит рисование, вы можете использовать хитрые приемы для повышения скорости рисования.напримерШахматную доску можно нарисовать, поочередно рисуя 64 белых и черных квадрата.Но зачастую быстрее нарисовать 32 белых квадрата, а затем 32 черных (поскольку вам придется менять цвет рисунка только дважды, а не 64 раза).Но на самом деле вы можете нарисовать всю доску черным, затем выполнить XOR 4 полосы по всей доске и 4 полосы вниз по доске белым, и это может быть еще намного быстрее (2 смены цвета и рисование только 9 прямоугольников вместо 64).Этот трюк с шахматной доской научит вас очень важному навыку программирования:Нестандартное мышление.Хорошо разработав свой алгоритм, вы часто можете существенно повлиять на то, насколько хорошо работает ваша программа.

Понимание C или, если уж на то пошло, любого языка программирования низкого уровня, дает вам возможность понять такие вещи, как использование памяти (т.е.почему плохо создавать несколько миллионов тяжелых объектов), как работают указатели/ссылки на объекты и т.д.

Проблема в том, что, создавая все более растущие уровни абстракции, мы обнаруживаем, что много программируем «лего-блоки», не понимая, как на самом деле функционируют лего.Имея почти бесконечные ресурсы, мы начинаем относиться к памяти и ресурсам как к воде и склонны решать проблемы, бросая в ситуацию больше железа.

Хотя это не ограничивается C, работа на низком уровне с гораздо меньшими системами с ограниченным объемом памяти, такими как Arduino или 8-битные процессоры старой школы, дает огромные преимущества.Это позволяет вам получить опыт, близкий к металлическому программированию, в гораздо более доступном пакете, и, потратив время на сжатие приложений в 512 КБ, вы обнаружите, что применяете эти навыки на более высоком уровне в своем повседневном программировании.

Таким образом, язык сам по себе не важен, но более глубокое понимание того, как все его части собираются вместе и как эффективно работать на уровне, близком к аппаратному обеспечению, — это набор навыков, полезных для любого разработчика программного обеспечения.

Во-первых, знание C поможет вам понять, как работает память в ОС и других языках высокого уровня.Когда ваша программа на C# или Java слишком сильно использует память, понимание того, что ссылки (которые по сути являются просто указателями) тоже занимают память, и понимание того, сколько структур данных реализовано (которые вы получаете, создавая свои собственные на C), поможет вам понять, что ваш словарь резервирует огромные объемы памяти, которые фактически не используются.

С другой стороны, знание C может помочь вам понять, как использовать функции операционной системы более низкого уровня.Вам это не нужно часто, но иногда вам могут понадобиться файлы с отображением в памяти или использование маршалинга в C#, и C очень поможет понять, что вы делаете, когда это происходит.

Я думаю, что C также помог мне понять сетевые протоколы, но я не могу указать конкретные примеры.На днях я читал еще один вопрос SO, где кто-то жаловался на то, что битовые поля C «по сути бесполезны», и я думал, насколько элегантно битовые поля C представляют низкоуровневые сетевые протоколы.Языки высокого уровня, работающие со структурами битов, всегда заканчиваются беспорядком!

В общем, чем больше вы знаете, тем лучшим программистом вы будете.

Однако иногда знание другого языка, например C, может заставить вас поступить неправильно, поскольку может возникнуть предположение, которое неверно для языка более высокого уровня (например, Python или PHP).Например, можно предположить, что определение длины списка может быть равно O(N), где N — длина списка.Однако во многих случаях языков высокого уровня это, вероятно, не так.В Python для большинства вещей, подобных спискам, стоимость равна O(1).

Знание больше о специфике языка поможет, но знание большего в целом может привести к неправильным предположениям.

Простое «знание» C не сделает вас лучше.

Но если вы понимаете все это, как работают нативные двоичные файлы, как с ними работает процессор, каковы ограничения архитектуры, вы можете написать код, который будет проще для процессора.

Например, как кэши L1/L2 влияют на вашу работу и как вам следует писать код, чтобы иметь больше обращений к кэшам L1/L2.При работе с C/C++ и серьезной оптимизации вам придется прибегать к таким вещам.

Дело не столько в знании C, сколько в том, что C ближе к «голому железу», чем многие другие языки.Вам нужно больше знать о том, как выделять/освобождать память, потому что вам придется делать это самостоятельно.Если вы сделаете это самостоятельно, вы сможете понять последствия многих решений, которые вы принимаете.

Для меня любой язык приемлем, если вы понимаете, как компилятор/интерпретатор (по сути) отображает ваш код на машине.Это немного проще сделать на языке, который предоставляет это напрямую, но вы сможете, немного почитав, выяснить, как распределяется и организуется память, какие шаблоны индексации более оптимальны, чем другие, какие конструкции более эффективен для конкретных приложений и т. д.

Я считаю, что более важным является хорошее понимание операционных систем, архитектур памяти и алгоритмов.Если вы понимаете, как работает ваш алгоритм, почему было бы лучше предпочесть один алгоритм или структуру данных другому (например, HashSet или HashSet).List) и то, как ваш код отображается на машине, не должно иметь значения, какой язык вы используете.

Это мой опыт того, как я изучал и учился программированию, в частности, пониманию C, это восходит к началу 1990-х годов, поэтому может быть немного устаревшим, но страсть и драйв важны:

  • Научитесь понимать низкоуровневые принципы работы компьютера, такие как программирование EGA/VGA, вот связь в архив Simtel в руководстве программиста C на ПК.
  • Понимание того, как работает TSR
  • Скачать весь архив Отрывки Боба Стаута это большая коллекция кода C, которая делает только одно - изучает их и понимает, не только это, коллекция фрагментов стремится быть переносимой.
  • Посетите Международный конкурс запутанного кода C (ОЦКЦ) онлайн, и посмотрите, как можно злоупотреблять кодом C, и разберитесь в тонкостях языка.Худшее злоупотребление кодом – победитель!Скачайте архивы и изучите их.
  • Как и мне самому, мне понравился пресловутый учебник Ponzo's C, который мне очень помог, но, к сожалению, архив очень трудно найти.Если кто-нибудь знает, где их получить, оставьте комментарий, и я исправлю этот ответ, включив ссылку.Есть еще один, который я помню - [Generic?] C Tutorial от Coronado, опять же, мои воспоминания об этом туманны...
  • Посмотрите на Др.Журнал Добба и журнал пользователя C здесь - Я не знаю, можно ли еще их распечатать, но они были классикой, помню ощущение, когда держу печатную копию в руке и отрываюсь домой, чтобы набрать код и посмотреть, что произойдет!
  • Возьмите древнюю копию Турбо С v2 который, я полагаю, вы можете получить на borland.com и просто поиграть с 16-битным программированием на C, чтобы почувствовать и разобраться с указателями... конечно, он древний и старый, но играть с указателями на нем - это нормально.
  • Понимать и изучать указатели, ссылка здесь к наследию Симтел.нет - решающее звено для достижения статуса гуру C, за неимением лучшего слова, также вы найдете множество загрузок, относящихся к языку программирования C. - Я помню, как заказал архив компакт-дисков Simtel и искал материалы C...

Несколько вещей, с которыми вам приходится иметь дело непосредственно в C, которые другие языки абстрагируют от вас, включают явное управление памятью (malloc) и работать непосредственно с указателями.

Моя подруга закончила один семестр после окончания Массачусетского технологического института (где в основном используют Java, Scheme и Python) по специальности «Информатика», и в настоящее время она работает в компании, чья кодовая база написана на C++.Первые несколько дней ей было трудно понять все указатели/ссылки/и т. д.

С другой стороны, переход с C++ на Java оказался для меня очень простым, поскольку меня никогда не смущало, что такое передача ссылок по значению или передача по ссылке.

Точно так же в C/C++ гораздо более очевидно, что примитивы — это просто компилятор, обрабатывающий одни и те же наборы битов по-разному, в отличие от таких языков, как Python или Ruby, где все является объектом со своими собственными отличными свойствами.

Простой (не совсем реалистичный) пример, иллюстрирующий некоторые из приведенных выше советов.Рассмотрим, казалось бы, безобидное

while(true)
   for(Iterator iter = foo.iterator(); iter.hasNext();)
       bar.doSomething( iter.next() )

или еще более высокий уровень

while(true)
    for(Baz b: foo)
        bar.doSomething(b)

Возможная проблема здесь заключается в том, что каждый раз вокруг пока в цикле создается новый объект (итератор).Если вас волнует только удобство программиста, то последнее определенно лучше.Но если цикл должен быть эффективным или машина ограничена в ресурсах, тогда вы в значительной степени зависите от разработчиков вашего языка высокого уровня.

Например, типичная жалоба на высокопроизводительную работу Java связана с остановкой выполнения во время удаления мусора (например, всех выделенных объектов Iterator).Не очень хорошо, если ваше программное обеспечение предназначено для отслеживания приближающихся ракет, автопилота пассажирского самолета или просто не заставляет пользователя задаваться вопросом, почему графический интерфейс перестал отвечать.

Одним из возможных решений (все еще на языке более высокого уровня) было бы ослабить удобство итератора до чего-то вроде

Iterator iter = new Iterator();
while(true)
    for(foo.initAlreadyAllocatedIterator(iter); iter.hasNext();)
       bar.doSomething(iter.next())

Но это имело бы смысл только в том случае, если бы вы имели какое-то представление о распределении памяти... в противном случае это выглядело бы просто как отвратительный API.Удобство всегда чего-то стоит, и знание вещей более низкого уровня может помочь вам выявить и снизить эти затраты.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top