Я думаю, что язык ассемблера может научить вас многим мелочам, а также нескольким большим понятиям.
Я перечислю здесь несколько вещей, о которых могу подумать, но ничто не заменит обучения и использования как x86, так и набора команд RISC.
Вы, вероятно, думаете, что целочисленные операции выполняются быстрее всего. Если вы хотите найти целочисленный квадратный корень из целого числа (т. Е. Floor (sqrt (i))), лучше всего использовать процедуру аппроксимации только для целых чисел, верно?
Нах. Математический сопроцессор (то есть на x86) имеет инструкцию fsqrt . Преобразование во float, получение квадратного корня и повторное преобразование в int быстрее, чем алгоритм из целых чисел.
Тогда есть такие вещи, как доступ к памяти, за которыми вы можете следить, но не оценивать должным образом, пока не углубитесь в сборку. Скажем, у вас есть связанный список, и первый элемент в списке содержит переменную, к которой вам нужно будет часто обращаться. Список переупорядочивается редко. Ну, каждый раз, когда вам нужно получить доступ к этой переменной, вам нужно загрузить указатель на первый элемент в списке, а затем, используя его, загрузить переменную (при условии, что вы не можете сохранить адрес переменной в регистре между использованиями) , Если вы вместо этого сохранили переменную вне списка, вам потребуется только одна операция загрузки.
Конечно, сохранение нескольких циклов здесь и там обычно не важно в наши дни. Но если вы планируете писать код, который должен быть быстрым, этот вид знаний можно применять как при встроенной сборке, так и, как правило, на других языках.
Как насчет соглашений о вызовах? (Некоторые ассемблеры позаботятся об этом за вас - настоящие программисты не используют их.) Очищает ли вызывающий или вызываемый объект стек? Вы вообще используете стек? Вы можете передавать значения в регистрах, но из-за забавного набора команд x86 лучше передавать определенные вещи в определенные регистры. И какие регистры будут сохранены? Компиляторы C не могут оптимизировать сами по себе - это вызовы.
Есть небольшие хитрости, такие как PUSHing адрес возврата и затем JMPing в процедуру; когда процедура вернется, она перейдет по адресу PUSHed. Этот отход от обычного мышления о вызовах функций является еще одним из тех «состояний просветления». Если вам когда-либо приходилось разрабатывать язык программирования с инновационными функциями, вы должны знать о забавных вещах, на которые способно аппаратное обеспечение.
Знание ассемблера учит вас особенностям компьютерной безопасности. Как вы можете использовать переполнение буфера или перейти в режим ядра, и как предотвратить такие атаки.
Кроме того, существует проблема самоизменяющегося кода и, как связанная с этим, механизмы для таких вещей, как перемещение и применение исправлений к коду (это также требует изучения машинного кода).
Но все эти вещи нуждаются в правильном уме. Если вы тот человек, который может поставить
while(x--)
{
...
}
с пользой, как только вы узнаете, что он делает, но вам будет трудно понять, что он делает сам, тогда язык ассемблера, вероятно, будет пустой тратой вашего времени.