Недавно я столкнулся с утверждением, которое меня сильно озадачило. Один программист с гордостью заявил, что не может понять ни малейшего куска кода, написанного им неделю назад. Я честно попытался понять, откуда исходит эта гордость, но так и не смог. Он гордился тем, что пишет столько кода каждый день? Это кто же готов платить ему за то, что он просто пишет код?
Проблемы с порядком байтов очень расстраивают, и я хочу избавить Вас от горя, которое довелось испытать мне. Вот ключевые тезы:
Проблема: Компьютеры, как и люди, говорят на разных языках. Одни записывают данные “слева направо” другие “справа налево”. При этом каждое устройство отлично считывает собственные данные — проблемы начинаются, когда один компьютер сохраняет данные, а другой пытается эти данные считать.
Решение: Принять некий общий формат (например, весь сетевой трафик передается в едином формате). Или всегда добавлять заголовок, описывающий формат хранения данных. Если считанный заголовок имеет обратный порядок, значит данные сохранены в другом формате и должны быть переконвертированы.
Самый простой способ для эпитета утратить свое первоначальное значение — это стать чрезмерно широким, начать означать чуть больше, нежели просто “мне это не нравится”. Речь идет о термине “спагетти-код”, который люди часто используют как синоним к понятию “плохой код”. Проблема в том, что не всякий плохой код является спагетти-кодом. Спагетти-код — это особенно опасный и специфический вид плохого кода, и его особое зло заключается в самом способе разработки нами программного обеспечения. Почему? Потому что отдельно взятые люди редко пишут спагетти-код самостоятельно. Скорее, определенный стиль в разработке делает его все более распространенным со временем. Для того, чтобы понять это, нужно рассмотреть первоначальный контекст, в котором было определено понятие “спагетти-код” — ужасное (и в основном архаичное) использование оператора goto.
В прошлый раз Аллан О’Доннелл рассказывал о том, как изучать С используя GDB. Сегодня же я хочу показать, как использование GDB может помочь в понимании ассемблера.
Уровни абстракции — отличные инструменты для создания вещей, но иногда они могут стать преградой на пути обучения. Цель этого поста — убедить вас, что для твердого понимания C нужно также хорошо понимать ассемблерный код, который генерирует компилятор. Я сделаю это на примере дизассемблирования и разбора простой программы на С с помощью GDB, а затем мы используем GDB и приобретенные знания ассемблера для изучения того, как устроены статические локальные переменные в С.
Исходя из особенностей таких высокоуровневых языков, как Ruby, Scheme или Haskell, изучение C может быть сложной задачей. В придачу к преодолению таких низкоуровневых особенностей C, как ручное управление памятью и указатели, вы еще должны обходиться без REPL. Как только Вы привыкнете к исследовательскому программированию в REPL, иметь дело с циклом написал-скомпилировал-запустил будет для Вас небольшим разочарованием.
Недавно мне пришло в голову, что я мог бы использовать GDB как псевдо-REPL для C. Я поэкспериментировал, используя GDB как инструмент для изучения языка, а не просто для отладки, и оказалось, что это очень весело.
Профессия программиста благословенна большим числом одаренных авторов. Сегодня я остановлюсь на трех моих любимых – Эрике Реймонде, Поле Грэме и Стиве Йегге. Сделаю я это потому, что они, как мне кажется, не сходятся со мной во мнении о том, что математика имеет (и будет иметь) значение для программиста-практика.