关于OF CF 标志位对于判定两整数大小关系(无符号数及有符号数情况)作用的讨论

在x-86 64 IA32 体系下,处理器通过对两数求差(保存或不保存结果)然后读取被改变的条件码来判定结果的正负,进而得知两整数大小关系。其背后的逻辑关系设计非常精妙,然而大部分书籍资料中都只是一笔带过。在此我做一个较为深入的讨论。讨论将分为两个部分,有符号整数和无符号整数,讨论重点集中在OF,CF两个标志位上。


有符号整数

        判断两个有符号数大小的关键在于OF(Overflow Flag),溢出标志位。运算出现溢出,则OF被置为1;反之则被置为0。对于有符号整数运算a - b = t, 若令b' 为b 的补码,相当于计算a + b' = t, 我们有(C语言表述):


OF = (a<0 == b'<0) && (t<0 != a<0);


(此处对a, b', t 正负性的判断基于符号位)。即,如果a 和 b' 同为负数或同为非负数,并且t 的符号与a, b' 的不同,则运算视为视为溢出。两个正数相加结果为负,则出现了正溢出(Positive Overflow);两个负数相加结果为正,则出现了负溢出(Negative Overflow)。在出现溢出的情况下,运算得到的结果与实际结果正负性相反,所以在条件码判断的时候就需要加上一个补偿。补偿的方式是,对于正负条件码SF(Sign Flag),我们用SF^OF替代(^为异或)。这样,在没有溢出发生的时候,OF = 0,没有任何影响;而当OF = 1,即有溢出发生的时候,SF^1 = ~SF,相当于获得的依然是正确的正负性判断。再加上ZF(Zero Flag)的帮助,我们有:

SF^OF == 1, 则有a

(SF^OF) == 0 且 ZF == 0, 则有a>b;

即,如果条件码显示结果t 为非负数,且不为零,则有a>b;如果结果为负数,则有a


无符号整数

        无符号整数比较的关键之处在于CF(Carry Flag),进位标志位。运算出现进位或借位,则CF被置为1;反之则被置为0。进位只会出现在加法运算中,比较运算是减法,只涉及到借位。然而我们会发现,由于减法也是通过加法间接实现的,所以此处的借位相当于没有进位,没有借位则说明进位了。具体来说,对于w 位的无符号整数运算a - b = t, 依然令b' 为b 的补码,我们有:

a - b = a + b'- 2^w

(此处^ 为指数运算符号)。这个关系来源于补码的性质,在无符号整数运算中,b + b' = 2^w。(在有符号运算中,才会有b + b' = 0)。所以,在无符号整数的运算中,由于使用运算结果a + b' 替代了真实结果a - b,我们其实是欠着一位的。2^w 相当于第 w+1 位上的”1“。所以,如果在这个加法运算中出现了进位,则相当于没有借位(还回去了),CF = 0;反之,若没有出现进位,则视为有借位,CF = 1。此时的CF就是借位的意思了,和无符号整数加法运算中表示进位的CF刚好相反。所以我们有(很显然):

CF == 1, 则有a

CF == 0 且 ZF == 0 则有a>b;

也就是基于无符号整数比较的seta, setb 等指令的判断根据。


PS:我们总共用到了四位标识符:SF,OF,ZF以及CF。ZF = 1则结果为零,a = b 这个结论过于明显所以上面没有提到。


你可能感兴趣的:(汇编)