1. 程式人生 > >關於OF CF 標誌位對於判定兩整數大小關係(無符號數及有符號數情況)作用的討論

關於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<b;

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

即,如果條件碼顯示結果t 為非負數,且不為零,則有a>b;如果結果為負數,則有a<b, 如果結果為零, 則有a=b。包括setg,setl 在內的涉及有符號整數比較的指令都是這麼判斷的。

無符號整數

        無符號整數比較的關鍵之處在於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<b;

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

也就是基於無符號整數比較的seta, setb 等指令的判斷根據。

PS:我們總共用到了四位識別符號:SF,OF,ZF以及CF。ZF = 1則結果為零,a = b 這個結論過於明顯所以上面沒有提到。