Какие есть конкретные примеры того, как знание C делает вас лучшим программистом высокого уровня? - PullRequest
14 голосов
/ 16 января 2010

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

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

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

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

Ответы [ 10 ]

15 голосов
/ 16 января 2010

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

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

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

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

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

9 голосов
/ 16 января 2010

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

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

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

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

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

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

5 голосов
/ 16 января 2010

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

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

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

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

2 голосов
/ 16 января 2010

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

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

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

2 голосов
/ 16 января 2010

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

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

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

1 голос
/ 16 января 2010

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

  • Научитесь понимать принципы низкого уровня компьютера, такие как программирование EGA / VGA, вот ссылка на архив Simtel в руководстве программиста на C для ПК.
  • Понимание того, как работает TSR
  • Загрузите весь архив фрагментов Боба Стаута , представляющих собой большую коллекцию кода на языке C, которая выполняет только одно - изучите их и поймите не только то, что коллекция фрагментов стремится быть переносимой.
  • Посмотрите онлайн на Международном конкурсе запутанного кода C ( IOCCC ) онлайн, и вы увидите, как можно злоупотреблять кодом C, и поймете внутренности языка. Худшее злоупотребление кодом - победитель! Скачайте архивы и изучите их.
  • Как и я, мне понравилось печально известное Учебное пособие C по Понзо, которое мне очень помогло, к сожалению, архив очень трудно найти. Если кто-нибудь знает, где их получить, оставьте комментарий, и я исправлю этот ответ, чтобы включить ссылку. Есть еще один, который я могу вспомнить - урок Coronado [Generic?] C, опять же, моя память об этом туманна ...
  • Посмотрите на журнал доктора Добба и C User Journal здесь - Я не знаю, можете ли вы получить их в печатном виде, но они были классическими, могу вспомнить ощущение, что я держал печатную копию в моем руку и отрывать домой, чтобы ввести код, чтобы увидеть, что происходит!
  • Возьмите древнюю копию Turbo C v2 , которую, я полагаю, вы можете найти на borland.com, и просто поиграйте с программированием на 16-битном C, чтобы почувствовать и испортить указатели ... конечно, это древний и старый, но играть с указателями на нем хорошо.
  • Поймите и изучите указатели, ссылку здесь на наследство Simtel.net - важнейшая ссылка для достижения C Гуру за отсутствием лучшего слова, также вы найдете множество загрузок, относящихся к языку программирования C - я помню, что на самом деле заказывал Simtel CD Archive и искал материал для C ...
1 голос
/ 16 января 2010

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

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

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

1 голос
/ 16 января 2010

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

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

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

0 голосов
/ 16 января 2010

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

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. Удобство всегда стоит где-то, а знание вещей более низкого уровня поможет вам определить и снизить эти затраты.

0 голосов
/ 16 января 2010

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

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

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

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

...