Принципиальная разница между test и cmp
версия для печатиВ результате выполнения инструкций ассемблера cmp и test меняется состояние флага нуля (ZF). Это все, что у них общего! Опасно считать эти инструкции похожими и тем более заявлять, что они обе выполняют сравнение. Под катом - основание столь дерзкого заявления :)
Почему вообще появилась эта статья. Постигаю азы ассемблера, читаю всякие источники. Когда первый раз узнал про команду cmp - это был разрыв шаблона! Утверждение, что при равенстве сравниваемых значений команда поднимает флаг нуля (ZF=1) для меня звучало, как парадокс. Позже разобрался, почему так. Потом читаю про якобы аналогичную команду test, и сказано в писании: в случае равенства сравниваемых значений сбрасывается флаг нуля! ЧОйРт побери, WTF?! Разобрался таки..
Важный момент: логика флага нуля (ZF). Он поднимается (равен единице), когда результат операции равен нулю, т.е. все биты результата - нулевые.
Инструкция cmp (сокр. от compare - сравнить) сравнивает два значения - регистр, память, непосредственное значение, - и устанавливает/сбрасывает флаг ZF. При этом процессор, получив инструкцию cmp, вычисляет разность указанных значений. Теперь должно быть понятно: если значения равны, то результат вычитания будет 0, следовательно поднимается флаг нуля (ZF=1). Пример:
xor ax,ax ;обнуляем регистр
mov ax,13d
add ax,7
cmp ax,20d ;значения равны => их разность=0 => флаг ZF=1
jz someLabel ;переход будет выполнен
Примечание: инструкция cmp отличается от аналогичной sub (substraction - вычитание) тем, что влияет только на регистр флагов.
Инструкция test. Получив такую команду, процессор выполняет операцию AND (логическое И) с двумя операндами. Т.е. выполняется побитовое логическое умножение. Если логическое И выдаст только нули, тогда поднимается флаг ZF. Инструкция test так же влияет только на регистр флагов, в этом ее отличие от инструкции AND. Пример:
xor ax,ax
mov ax,0011b
test ax,0010b ;результат будет не нулевой (второй бит будет равен 1) => ZF=0
jnz someLabel ;флаг нуля сброшен, будет переход
Выводы: во-первых, cmp и test влияют на флаг нуля противоположным образом. Во-вторых, команду test нельзя использовать для проверки равенства значений! Пример:
mov eax,5
test eax,5 ;установит флаг ZF=0
jnz someLabel ;переход выполнится
...
test eax,4 ;так же установит флаг ZF=0
jnz someLabel ;переход опять выполнится
Сравниваем одинаковые/разные числа, а переход выполняется в любом случае! Если вместо test поставить cmp, то первый переход не выполнится. Почему такие странности с test? Смотрим запись чисел в двоичной СИ:
5(10)=0101(2)
4(10)=0100(2)
Результат инструкции test:
test 5,5: 0101 AND 0101=0101
test 5,4: 0101 AND 0100=0100
В результатах обоих операций есть биты равные единице, поэтому флаг нуля не понимается. Вот поэтому нельзя полагаться на такое сравнение значений.
Итак, команда test применяется для битовой проверки состояния флагов и т.п. Есть еще одно применение - проверка нулевого значения регистра:
test eax,eaxjz someLabel ;переход выполнится только если eax=0
Объяснил, как смог :) Сам долго не мог постичь логику, особенно считая, что test и cmp - похожие по назначению команды. Надеюсь, разница понятно изложена.
[1oo%, EoF]Понравилась статья? Расскажите о ней друзьям: