我理解进位和溢出标志的使用存在于算术中的错误检查,但为什么零标志对系统/程序员有用呢?
p1tboqfb1#
任何计算机都有一个非常常见的任务,就是比较两个整数(或指针)的大小,并根据结果进行条件跳转,这就是实现if (x < y)、if (x == y)等高级结构的方法。在x86上,如同在许多其它架构中一样,此任务被分解为两个指令:CMP或类似的指令来执行比较运算,而条件Jcc指令则执行跳转。CMP必须在CPU中有某种状态,才能将其结果传送给Jcc使用,这就是FLAGS寄存器的作用。对于相等性的测试是这些操作中最基本的,因此应该存在根据CMP的两个操作数是否相等而设置的标志是有意义的。由于CMP实际上是隐藏的减法操作,因此这等效于询问减法的结果是否为零,这在硬件中很容易实现,通过对所有的位进行“或”运算,然后将一位的结果取反。这就是零标志。因为它基本上不需要花费什么,8086的设计者决定在几乎每个算术或逻辑指令之后,而不仅仅是在X1 M9 N1 X之后,以这种方式设置零标志。那么“如果相等就跳转”就等同于“如果设置了零就跳转”。实际上,JE和JZ只是同一条机器码指令的不同汇编助记符。其他标准算术标志(进位、符号、溢出)也是以这种方式使用的。到目前为止,这是它们比任何一种错误检查更常见的用法。(实际上,许多编译语言并不进行这样的错误检查,而是在发生溢出时简单地忽略溢出。)例如,如果您希望跳转if AX < BX(其中寄存器中的值将被视为无符号),你可以从AX中减去BX,如果出现借位则跳转,这在x86上设置进位标志。2那么你的代码看起来就像CMP AX, BX / JC label。3汇编程序允许你使用JB而不是JC,这样你就可以把它看作是“如果低于则跳转”。4你也可以把它和零标志结合起来;如果要在AX <= BX时跳转,则写入CMP AX, BX ; JBE label,其中JBE将在设置进位或零标志中的 * 任一 * 时跳转。符号和溢出标志类似地用于有符号比较,但规则稍微复杂一些。
if (x < y)
if (x == y)
CMP
Jcc
FLAGS
JE
JZ
AX < BX
CMP AX, BX / JC label
JB
JC
AX <= BX
CMP AX, BX ; JBE label
JBE
ibps3vxo2#
这些标志远比仅仅从CMP中产生有用。“如果(!--x){...}这可以很容易地用DEC/JZ对实现,而不需要任何中间CMP。
2条答案
按热度按时间p1tboqfb1#
任何计算机都有一个非常常见的任务,就是比较两个整数(或指针)的大小,并根据结果进行条件跳转,这就是实现
if (x < y)
、if (x == y)
等高级结构的方法。在x86上,如同在许多其它架构中一样,此任务被分解为两个指令:
CMP
或类似的指令来执行比较运算,而条件Jcc
指令则执行跳转。CMP
必须在CPU中有某种状态,才能将其结果传送给Jcc
使用,这就是FLAGS
寄存器的作用。对于相等性的测试是这些操作中最基本的,因此应该存在根据
CMP
的两个操作数是否相等而设置的标志是有意义的。由于CMP
实际上是隐藏的减法操作,因此这等效于询问减法的结果是否为零,这在硬件中很容易实现,通过对所有的位进行“或”运算,然后将一位的结果取反。这就是零标志。因为它基本上不需要花费什么,8086的设计者决定在几乎每个算术或逻辑指令之后,而不仅仅是在X1 M9 N1 X之后,以这种方式设置零标志。那么“如果相等就跳转”就等同于“如果设置了零就跳转”。实际上,
JE
和JZ
只是同一条机器码指令的不同汇编助记符。其他标准算术标志(进位、符号、溢出)也是以这种方式使用的。到目前为止,这是它们比任何一种错误检查更常见的用法。(实际上,许多编译语言并不进行这样的错误检查,而是在发生溢出时简单地忽略溢出。)例如,如果您希望跳转if
AX < BX
(其中寄存器中的值将被视为无符号),你可以从AX中减去BX,如果出现借位则跳转,这在x86上设置进位标志。2那么你的代码看起来就像CMP AX, BX / JC label
。3汇编程序允许你使用JB
而不是JC
,这样你就可以把它看作是“如果低于则跳转”。4你也可以把它和零标志结合起来;如果要在AX <= BX
时跳转,则写入CMP AX, BX ; JBE label
,其中JBE
将在设置进位或零标志中的 * 任一 * 时跳转。符号和溢出标志类似地用于有符号比较,但规则稍微复杂一些。
ibps3vxo2#
这些标志远比仅仅从CMP中产生有用。“如果(!--x){...}
这可以很容易地用DEC/JZ对实现,而不需要任何中间CMP。