CF, ZF, SF и OF являются единичными битами в регистре CC (код условия). Есть и другие биты, которые устанавливаются при других условиях. Всякий раз, когда ЦП выполняет определенные инструкции (включая add
и sub
), он устанавливает эти биты в соответствии с результатом операции. Инструкции cmp
и test
действуют идентично инструкциям sub
и and
соответственно, за исключением того, что они полностью отбрасывают результат, и единственным выходом являются флаги условий.
Предположим, у нас есть следующий код C:
int a, b;
...
a -= b;
if(a < 0)
{
// stuff...
}
Наивный компилятор может скомпилировать это так:
; Suppose a is in the eax register and b is in the edx register
sub %eax, %edx ; subtract b from a, store result in a
cmp $0, %eax ; compare a to 0
jl end_of_stuff ; if a < 0, goto end_of_stuff
; code for stuff goes here
end_of_stuff:
; code after if block goes here
Более умный компилятор, однако, поймет, что инструкция sub
уже устанавливает коды условий, поэтому он может скомпилировать ее следующим образом:
sub %eax, %edx
jl end_of_stuff ; if a < 0, goto end_of_stuff
; code for stuff goes here
end_of_stuff:
; code after if block goes here
Обратите внимание, что инструкция jl
(переход, если меньше, чем) выполняет переход, если и только если SF ≠ OF. То есть он скачет, если результат отрицательный и переполнения не произошло, или если результат положительный и переполнение произошло. Это необходимо для обеспечения получения правильного результата при переполнении разницы (например, сравнение INT_MIN
с INT_MAX
).