有学生给我一段程序,就在运行中标志位的“怪异”表现提出问题。
程序不难懂:
assume cs:codesg
codesg segment
start:
mov al,0fch
add al,05h ;结果不溢出
mov al,0f5h
add al,87h ;结果溢出
mov ax,4c00h
int 21h
codesg ends
end start
难懂的是,运行后,观察到的标志位不对劲!
完成0FCH+05H,其和为101H,很显然有进位(CY),但如画红圈的地方,无溢出(NV)。不算是溢出!
而继续运行程序,再观察标志位的变化:
完成0F5H+87H,其和为17CH,仍有进位(CY)好理解,此时是有溢出(OV)。
同样有进位,一个是无溢出,一个是无溢出,作何解释?Debug坏了,还是CPU烧了?
都没有!
(1)进位:说进位,针对的是无符号数,8位的无符号数,其范围是0~255
,即0~0FFH
。当无符号数运算超出了这个上下限,就产生了“进位”。上面的两个运算都超出了这个范围,所以上述两种情况都有进位。
(2)溢出:说溢出,针对有符号数! 8位的有符号数,其范围是-128~127
,其最高位是符号位,1
表示负数,0
表示正数。有符号数运算超出这个上下限,将产生“溢出”。0FCH+05H,其和为101H,即-4+5得1,无溢出;0F5H+87H,其和为17CH,即(-11)+(-121)得124,这是超出了原运算数的范围!这是溢出!
理解的难点就在这里了。0FH是-11D,87H是-121D,7CH是124D,这个按补码定义推一推不难,难理解的是,同样产生了进位(这实际上是无符数的概念),在溢出(有符号数中的概念)上出了差异。
0FCH+05H,其和为101H,即-4+5得1,把那个“进位”的1扔掉后,恰得到作为有符号数而言正确的答案;而0F5H+87H,其和为17CH,即(-11)+(-121)得124,把那个“进位”的1扔掉后,恰得到作为有符号数而言错误的答案,标志位恰巧解决的是这样的问题!
写到这儿,由不得感恩这一套规则的设计者,原来无论进位、溢出,都是为出现“异常”情况提供的警示!在其规定的意义角度没有问题,标志位不变,只有当有问题时,才会用自己的变化,提醒计算者——这里不正常!
问题解答完了。实际上,这里看到的现象,恰是补码原理的精要,计算机中用补码,解决的也就是这样的问题。
本文用大白话,具体的实例说明了这件事情,实际上,若用形式化的方法描述和解释,会更透彻。只可惜,我不用数学方法表达太久了,也放弃这个于我而言显费力的事了。
感谢我的学生李振昊,发现了这个现象,并向我提问。