2.2 整數表示(以及轉換)
本節要使用到的公式/函數術語(引用原文圖片)
圖中的w表式二進制的位數
一.無符號整數的編碼
這裏引用原文中的圖片
可見,無符號整數的十進制表示就是將所有的二進制位乘以權值然後求和轉換爲十進制。
無符號數的範圍:0~2w-1。(最小值,全0;最大值,全1)
舉個例子:爲了簡單,使用四位二進制表示
無符號數[1111] = 8 + 4 + 2 + 1 = 15
二.補碼編碼(有符號整數的編碼)
這裏引用原文中的圖片
可見,通過補碼錶示整數時,最高位的權值是一個負值。
舉個例子:補碼數[1111] = -8 + 4 + 2 + 1 = -1
補碼數的範圍:-2w-1 ~ 2w-1-1(最小值:最高位爲1,其餘位全爲0,因爲最高位的權值爲負,其餘位的權值爲正,一個最小值,加上正數就不是最小了;最大值爲最高位爲0,其餘位爲1)舉個例子:對於4位補碼數而言,最小值[1000](-8),最大值[0111](7)
通過補碼數的範圍,也可以知道,|TMax| = |TMin| - 1
三.原碼和反碼
反碼最高位的位權是-(2W-1-1),其餘的位權和補碼數一樣
原碼的最高位表示符號位,其餘位表示值
原碼[0111] = 7
原碼[1111] = -7
四.原碼,反碼,補碼間的關係
對於三種編碼來說,它們的區別就是最高位的含義不同
原碼:最高位不表示權值,表示數的符號。
反碼:最高位表示權值,是補碼數最高位權值加1
補碼:最高位便是權值,是無符號數最高位權值的相反數
因此,對於大於0,等於0,小於0這三種情況,編碼各有差異,如下圖
五.補碼數和無符號數之間的轉換
對於二進制位數相同的情況,補碼數和無符號數之間的轉換可能改變值,但不會改變位模式。也就是說,對於符號鍵的轉化,其實什麼都沒做,僅僅改變了解釋的方式
舉個例子:仍然使用4位二進制爲例
無符號[1111] = 8 + 4 + 2 + 1 = 15
補碼數[1111] = -8 + 4 + 2 + 1 = -1
對於無符號的[1111]來說,若轉換成補碼數,僅僅改變了解釋的方式(補碼數的最高位的權值是無符號數最高位權值的相反數),也就是說,改變了計算的方法,但是位模式是完全一致的。
由於C中,整數最少用8位表示,所以用8位的整數舉個例子
位模式[1111 1111] = 無符號整數255 = 補碼數-1
六.位模式的擴展與截斷
擴展:
一個位數較少的類型,轉換成一個位數較多的類型時,就會進行擴展。對於無符號數來說,採用0擴展(也就是補0);對於補碼數來說,採用符號擴展(也就是使用位數較少的最高位來補)。
舉個例子:使用4位二進制爲例,擴展到8位
無符號[1010] = 無符號[0000 1010] = 10
有符號[0101] = 有符號[0000 0101] = 5 有符號[1010] = 有符號[1111 1010] = -6
擴展改變了位模式,但不會改變值
截斷:
一個位數較多得類型,轉換成一個位數較少的類型,就會截斷。 無符號數和補碼數採用相同的策略:捨去高位
舉個例子:8位截斷到4位
[1010 1010] -> [1010]
截斷改變了位模式,同樣也改變了值
既改變類型(有符號與無符號),又改變位模式的情況
用兩個例子來看一下:由於C沒有直接的二進制表示,所以用16進制代替。
再說一點,使用%x輸出時,會自動擴展到32位,使得結果並不明顯。
首先來看擴展,
再來看截斷,
結論:先進行二進制位模式的擴展/截斷。經過擴展/截斷之後,再進行相同位數的類型轉換
其實,只進行了擴展/截斷(如果是擴展,根據轉換前的類型進行擴展),因爲相同長度的類型轉換隻是改變解釋的方式
七.C中因爲類型轉換的一些詭異的代碼
int main(void){
printf("%d", (-1 < 1u));
return 0;
}
竟然會輸出0(表達式爲假)
在C中,如果一個表達式中出現了無符號數,則會將所有的有符號數轉換成無符號數,在進行求值