Люди часто думают, что код на ассемблере читается не просто плохо, а очень плохо. Но я думаю, что это совершенно не так. Я всегда считал, что читаемость кода на совести программистов и язык здесь совершенно не причём. Так вот, когда работал над одним из своих проектов, мне понадобился алгоритм для поиска следующего или предыдущего листа дерева. Алгоритм тривиальный, но реализация получилась такой компактной и простой, что решил опубликовать её в качестве иллюстрации того, что на ассемблере можно (и нужно) писать удобочитаемый код. Честно говоря, я сомневаюсь, что на языке высокого уровня можно написать это более компактно и понятно. Но возможно я ошибаюсь. Увидим далее в статье. Дерево для которого писался код, является упорядоченным, двусвязным и с произвольным количеством дочерних узлов. Каждый узел, описывается следующей структурой: Все дочерние узлы родительского узла образуют двусвязный список (поля .next, .prev). Родительский узел указывает только на начало и конец этого списка, соответственно через указатели .f_child и .l_child. Задача: По заданному листу дерева, надо найти следующий лист. Если лист последний, найти первый лист дерева. Это показано на Фиг.1; Синим пунктиром изображены связи через .prev и .next, черными линиями связи через .parent, .f_child и .l_child, а красными линиями, изображена последовательность переходов по алгоритму. А вот и сам код в девяти инструкциях: У этого кода есть только один изъян. Если у дерева есть несколько корневых узлов, то алгоритм не будет переходить правильно от последнего к первому листу. Конечно, это уже будет не одно дерево, а несколько несвязанных между собой деревьев (точнее связанные только через .prev и .next). Но структура позволяет такое, так что было бы хорошо, если алгоритм корректно работал с такими деревьями. Этого можно достичь, добавив еще три инструкции. А точнее, те же три инструкции еще раз: Тот же самый код можно использовать и для поиска предыдущего листа, поменяв prev на next и f_child на l_child: Вы наверное заметили, что весь код состоит из одинаковых триплетов: Это дополнительно увеличивает удобочитаемость кода. Достаточно однажды понять, как эти три инструкции работают в связке, чтобы понять весь код. А теперь давайте сравним этот код с эквивалентным кодом на C++. У меня, с трудом (я не силён в C++), но получилось как-то так: Структура: И сам код: Я оставил только код, который непосредственно делает работу. Постарался оформить его, так, чтобы был более читабельным. Но все равно, ассемблерный код читается легче. В коде на C++ нет никакого общего шаблона. Чтобы понять, как он работает, надо рассматривать каждую линию в отдельности и в связке с остальными. А может это мне только кажется и зависит от знания языка? Или этот код можно написать лучше? Компилировал так: Результатом компиляции стал следующий код (я намерено использовал те же самые метки как в ассемблерном коде, чтобы легче было сравнивать): Надо сказать, что код получился достойным. Не идеальным для чтения, но этого от компилятора и не требуется. Но даже этот неидеальный код, мне кажется, читается лучше, чем оригинальный код на C++. Напишите в комментариях, считаете ли вы ассемблерный код сложным для чтения? А что вам мешает – незнание языка, программисты, которые пишут плохо читаемый код, или вы думаете, что это свойство ассемблера и ничего нельзя сделать в принципе? Инженер автоматизации