汇编语⾔中数⼤⼩的⽐较
(这篇⽂章对本⼈收获很⼤推荐)
摘要:在汇编语⾔中,对于数据谁⼤谁⼩的判断是经常会碰到的,数⼤⼩的判断包括判断两个⽆符号数之间的⼤⼩,也包括判断两个带符号数之间的⼤⼩,对于前者的判断可通过进位标志位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(负)时,说明两个数是前者⼤于或等于后者。
比较指令cmp怎么用
②如果结果是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 ;保存结果
-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,结果没有溢出,所以实际结果的负数和逻辑结果上的负数⼀致,结果正确。若是溢出了,那么实际结果和逻辑结果的正负性就是相反的。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。