本文来源于 www.14edu.com(论文网) 原文链接:http://www.14edu.com/ligong/jisuanji/ligong/rjgc/0RX01152010_2.html
(这篇文章 对本人收获很大 推荐)
摘要:在汇编语言中,对于数据谁大谁小的判断是经常会碰到的,数大小的判断包括判断两个无符号数之间的大小,也包括判断两个带符号数之间的大小,对于前者的判断可通过进位标志位CF来判断,但对于后者却要涉及到对符号标志位SF以及溢出标志位OF这两个状态标志位的综合分析,所以这两种数的处理方法是不一样的,如果混为一谈是很容易出错的,因此数大小的判断在汇编中必须值得注意。
在汇编语言里,对于数来说,可以将它们分成带符号数和无符号数,顾名思义,带符号数就是数的最高位为符号位,其余的为数值位;相反,若最高位不是符号位则称作为无符号数;但数的大小比较是不是也要分为这两种呢?也就是无符号数和带符号数的比较呢?下面就几个状态标志位来讨论一下。
1 讨论
1.1 标志寄存器FLAGS
标志(Flag)用于反映指令执行结果或控制指令执行形式。它是汇编语言程序设计中必须特别注意的一个方面。许多指令执行之后将影响有关的标志位;不少指令的执行要利用某些标志;当然,也有很多指令与标志无关。
8086有一个16位的标志寄存器FLAGS(其中存储的信息被称为程序状态字寄存器PSW:Program Status Word)。标志寄存器的标志有两类:6个状态标志和3个控制标志。
下面就简单介绍一下跟数的符号以及数的大小相关的几个状态标志位:
SF (Sign Flag): 符号标志位。它记录相关指令执行后,其结果是否为负。
CF (Carry Flag): 进位标志位。它记录了无符号数运算结果的最高位向更高位的进位值,或从更高位的借位值。
OF (Overflow Flag): 溢出标志位。它记录了有符号数运算的结果是否发生了溢出。
我们知道,数据处理是计算机的的基本功能之一,那么这些需要处理的数据是如何在计算机中表示的呢?
日常生活中,人们习惯使用十进制来表示数据,而计算机中采用的却是二进制数,并且可将数据分为无符号数与带符号数,无符号数全部的位都是数值位,而带符号数在最高位是符号位,若为1,则该数为负数,反之则为正数;而跟数据大小有关的标志位包括了CF、SF和OF。
1.2 进位标志位CF
当进行加减运算时,若高位发生进位或借位,则CF为1,否则为0。该标志位通常用于判断无符号数运算结果是否超出了计算机所能表示的无符号数的范围。
例如:255-67,这个减法中,被减数对应十进制数255,而减数是67,通过结果显示,最高位是0,说明该减法没有发生借位,此时CF=0,表示被减数是大于减数。从结果来看,是在0~255之间,没有超过范围,结果是正确的。
又再如:67-255,在这个减法中,被减数是67,减数是255,结果显示最高位是1,说明减法发生了借位,此时CF=1,表示被减数是小于减数。从结果来看,并不是在0~255之间,超过了范围,说明结果是错误的。
比如有一比较两无符号数大小的编程题:
有两个字节型无符号数分别放在X和Y两存储单元中,试比较两数大小,并且将较大者放在X单元里。源程序如下:
MOV AL, X
CMP AL, Y
JNC NEXT (或 JBENEXT) ;若X等于或等于Y,则AL直接存回X
MOV AL, Y ;若X小于Y,则是将Y的值存入X
NEXT: MOVX, AL
从上面的分析可以得知,对于无符号数的大小比较关键是看CF的值。若CF=0,说明前者大于后者,反之则是后者大于前者。
1.3 符号标志位SF
前面介绍的是无符号数,对于带符号数,在计算机中是以补码的形式存放的,就拿简单的字节型数据来说,它所表示十进制数的范围是-128~ 127,现在来看一下字节型带符号数大小的比较:-1-(-2),从结果可以得知,最高符号位是0,表示差值是一个正数,对应十进制数 1,而在式中,被减数是-1,减数是-2,显然前者大于后者,所以可以判断结果是正确的。如果这两个数的位置对调一下,差值是11111111,对应十进制数-1,所以结果也是正确的。
1.4 溢出标志位OF
先来看一下什么是溢出——如果运算结果超出能够表达的数据范围,就产生了溢出。而处理器内部以补码表示带符号数,8位表达的整数范围是: 127~-128,16位表达的范围是: 32767~-32768。
对于前一部分所列举的例子一个是-1减-2,结果没有溢出,另外一个是-2减-1,结果也没溢出。
现在来看一下如果结果发生了溢出又是如何来判断两个带符号数的大小的。例如:
-3-( 126)。结果7FH SF=0(正),且OF=1,可以看出结果是错误的,但是这两个条件却能说明前者小于后者;再来看个例子: 3-(-126),所得结果 8 1H SF=1(负),且OF=1,可以看出结果也是错误的,但是这两个条件却说明了前者大于后者。
如果OF=0 有-3-(125)= -128(未溢出)SF= 1;
3-(-124)=127(未溢出) SF=0
故
OF=0 SF=0 前> 后
OF=0 SF=1 前< 后
OF=1 SF=0 前< 后
OF=1 SF=1 前> 后
2 小结
通过以上的几个关于带符号数大小比较的例子来看,不能简单地归纳为:如果SF=1,就意味着前者一定小于后者,反过来SF=0就一定是前者大于或等于后者。对于带符号数,其大小的比较的规律比无符号数(只要看进位标志位CF的值)要更复杂,它不能仅仅只看一个状态标志位——符号标志位SF,还得要看另外一个重要的标志位——溢出标志位(OF),应该归纳如下:
1)无符号数的比较:
① CF=0,前者大于或等于后者;
② CF=1,前者小于后者;
2)带符号数的比较:
① 如果结果是OF=0,且SF=0(正),或者当OF=1,且SF=1(负)时,说明两个数是前者大于或等于后者。
② 如果结果是OF=0,且SF=1(负),或者当OF=1,且SF=0(正)时,说明两个数是前者小于后者。
在用比较指令CMP来实现两个无符号数大小比较时,条件转移指令应当涉及到以下三个字符:A(Above高于)、B(Below低于)、E(Equal等于),包括JA(JNBE)、JAE(JNB)、JB(JNAE)、JBE(JNA),或者用减法指令SUB来实现两个无符号数大小比较时,会涉及到带CF的条件转移指令:JC和JNC;而在用比较指令CMP实现两个带符号数大小比较时,条件转移指令涉及却是另外三个字符:G(Greater大于)、L(Less小于)、E(Equal等于),包括JG(JNLE)、JGE(JNL)、JL(JNGE)、JLE(JNG),或者用减法指令SUB来实现两个带符号数大小比较时,会涉及到带SF和OF的条件转移指令:JS、JNS和JO、JNO。
例:计算|X-Y|,X和Y为存放于X单元和Y单元的8位带符号数数,结果存入result。
MOVAL, X
SUB AL, Y ;AX←X-Y,下面求绝对值
JNS NONNEG ;为正数,无需处理,直接转向保存结果
NEGAX ;为负数,进行求补得到绝对值
NONNEG: MOVresult, AL;保存结果
乍一看,这程序好像无可挑剔,但是如果X=-2,Y= 127的话,SF=0,满足条件转到标号NONNEG,显然这是错误的,应当是这个差值先要求补,再保存结果。究其原因,它没有考虑是否会发生溢出,其程序应当做如下修改:
MOVAL, X
SUBAL, Y ;AX←X-Y,下面求绝对值
JNONEXT ;先判断是否溢出,若未溢出,接着判断符号位SF
JS NONNEG ;溢出,且结果为负时,直接保存结果
JMPFAN ;溢出,且结果为正时,要先求补
NEXT:JNS NONNEG ;未溢出,且结果为非负时,直接保存结果
FAN:NEGAL ;未溢出,且结果为负时,要求补
NONNEG:MOVresult, AL ;保存结果
本文来源于 www.14edu.com(论文网) 原文链接:http://www.14edu.com/ligong/jisuanji/ligong/rjgc/0RX01152010_2.html
-1 -2 -3 -4 。。。 -127 -128
0 1 2 。。。 126 127
一些运算、比较类指令会影响到相应的标志位,如CF、OF、SF。
如上图,我自己定义加法运算为顺时针,减法运算为逆时针。
加减法运算分为两种,一种是有符号数运算;另一种是无符号数运算。
无符号数运算会影响进位或借位标志 CF。
而标志位 OF 和 SF 则会在带符号运算中受到影响。
其实,系统在进行一个运算指令时,是同时在进行两种运算的,这两种运算的结果通过相关的标志位反应出来。
带符号位运算实质:
符号数的范围是(-128 ~ 0 < 80H ~ 0> )(0 ~ 127 < 0 ~ 7FH> )。
exp1:
mov ah, 22h
mov bh, 0a0h
sub ah, bh
按无符号数运算来看 22 < a0h ,所以要产生借位,此时 CF = 1,结果为 82H;
按有符号运算来看,结果仍然是82H,82H为负数。一个正数减去一个负数,实际就是加法运算,按上图,应该顺时针旋转。但是82H越过正数的最大边界7FH(127),所以产生了溢出,故OF = 1。因为 SF 只和运算结果想联系,82H为负数,结果 SF = 1。
假如仅从 SF 和 OF 来看,SF = 1,则说明运算结果为负数。但此时 OF 也为1,表明发生了溢出。溢出的说法是,本来应该是正数的,一旦发生了溢出,就会变成负数;反之,本来要是负数的结果,发生了溢出,结果就变成了正数。
exp2:
mov ah,0a0h
mov bh,0cbh
cmp ah,bh
分析:
cmp 的本质是进行减法运算。
按照无符号运算,a0h 小于 cbh ,所以要产生借位,CF = 1。运算在ah中的结果为:D5。
-53 的补码为 0CBH 。-96 的补码为 a0h。a0h - 0cbh 就相当于 -96 - (-53)= -96 + 53= -43,而 -43 的补码为 D5 。从图上看,就是从 A0的位置,顺时针旋转 53 个单位,然后停留在 D5H 处,这里并没有超越边界0 ,所以没有产生溢出,故 OF = 0;结果仍然为负数,所以 SF = 1。
仅从 OF 和 SF 观察,SF = 1,知道结果为负数;OF = 0,结果没有溢出,所以实际结果的负数和逻辑结果上的负数一致,结果正确。若是溢出了,那么实际结果和逻辑结果的正负性就是相反的。