1.概念
在計算機中,可以區分正負類型的數,成爲“有符號數”(signed);無正負類型的數(只有整數類型),成爲“無符號數”(unsigned)。簡明的說,無符號說就是其所有的位數都用來表示數值的大小,有符號數除最高位來表示數值的正負外(0表示正數;1表示負數),其餘各位用來表示數值的大小。舉個例子說明一下:十機制數 正數255 二進制表達形式:1111 1111
十機制數 負數-1 二進制表達形式:1111 1111
可見-1的二進制的最高位爲紅色的1,可是爲什麼其表達形式爲1111 1111而不是1000 0001呢?這就關於任何數在計算機內是以補碼形式存儲問題。下面會介紹的,在此先不詳細說明了。
2.存儲範圍
從前面的介紹可以知道,由於有符號數的最高位被拿來用作符號位,所以它所能夠表達的最大數值要小於無符號數所能夠表達的最大數值。還是舉個例子來說明一下吧:
無符號數:1111 1111 十進制值:255
有符號數:0111 1111 十進制值:127
這是有人可能會提出這樣的疑問:有符號數所能夠表達的數值範圍會不會小於無符號數所能夠表達的數值範圍呢?
呵呵,答案是否定的!雖然有符號數在表達最大值上的能力減弱了,但是它能夠表達負數。負數的個數可以彌補其不足。來讓我們比較一下:
一個字節的無符號數的表達數值範圍是:[0,255]
一個字節的有符號數的表達數值範圍是:[-128,0),[0,127]
可見它們都能夠表示256個數。
3.各種碼(原碼/反碼/補碼)
有些人也許會這樣認爲"-1"(雙字節)在計算機中的表達形式爲1000 0000 0000 0001,可是實際上不是的。計算機是以其補碼的形式進行表達的,即“-1”(雙字節)的表達形式是1111 1111 1111 1111。
說一下各種碼的概念吧。
原碼:一個整數,按照絕對值的大小轉換成二進制數,最高位爲符號位。
反碼:將原碼除最高位(符號位)外,其餘各位按位取反,所得到的二進制碼。正數的反碼爲原碼。
補碼:反碼最低位加1即爲補碼。
關於負數的補碼求法說明一下,先得到其反碼,之後將反碼加1即可。有些大神根據其原碼,閉眼即得,這種能力需要修煉一下啊。
這時有些人可能會說,爲什麼要引入補碼的形式呢?直接按照原碼存儲不就省事很多嗎?嘿嘿,要記住,有些事情並不是你想省事就能省事的。好了來欣賞一下補碼的優勢吧。
計算機的帶符號數用補碼錶示的優點:
1負數的補碼與對應正數的補碼之間的轉換可以用同一種方法-求補運算完成,可以簡化硬件。 2 可將減法變爲加法,這樣減法就可以用加法器進行計算了。 3 兩個用補碼錶示的數相加時,如果最高位(符號位)有進位,則進位被捨棄。心算求補(大神求補算法):
從最低位開始至找到的第一個1均不變,符號位不變,這之間的各位“求反”(0變1;1變0)。
原碼:1010 1001 補碼:1101 0111.
4.有符號數與無符號數的相互轉換
無符號整數和有符號整數之間進行強制類型轉換時,位模式不改變。
有符號數轉換爲無符號數時,負數轉換爲大的正數,相當於在原值上加上2的n次方,而正數保持不變。
無符號數轉換爲有符號數時,對於小的數將保持原值,對於大的數將轉換爲負數,相當於原值減去2的n次方。
當表達式中存在有符號數和無符號數類型時,所有的操作都自動轉換爲無符號類型。可見無符號數的運算優先級高於有符號數。
unsigned int a = 20; signed int b = -130;
運算一下結果是 b>a 。
5.轉換大餐
有符號數的轉換
原類型 | 目標類型 | 轉換方法 |
char |
short |
符號位擴展 |
char | long | 符號位擴展 |
char | unsigned char | 最高符號位失去位意義,變爲數據位 |
char | unsigned short | 符號位擴展到short;然後從short轉到unsigned short |
char | unsigned long | 符號位擴展到long;然後從long轉換到unsigned long |
char | float | 符號位擴展到long;然後從long轉到float |
char | double | 符號位擴展到long;然後從long轉換到double |
char | long double | 符號位擴展到long;然後從long轉換到long double |
short | char | 保留低位字節 |
short | long | 符號位擴展 |
short | unsigned char | 保留低位字節 |
short | unsigned short |
最高爲失去意義,變爲數據位 |
short | unsigned long | 符號位擴展到long;然後從long轉到unsigned long |
short | float | 符號位擴展到long;然後從long轉到float |
short | double | 符號位擴展到long;然後從long轉到double |
short | long double | 符號位擴展到long;然後從long轉換到long double |
long | char | 保留低位字節 |
long | short | 保留低位字節 |
long | unsigned char | 保留低位字節 |
long | unsigned short | 保留低位字節 |
long | unsigned long | 最高爲失去意義,變爲數據位 |
long | float | 使用單精度浮點數表示,可能失去精度 |
long | double | 使用單精度浮點數表示,可能失去精度 |
long | long double | 使用單精度浮點數表示,可能失去精度 |
無符號數的轉換
原類型 | 目標類型 | 轉換方法 |
unsigned char | char | 最高爲作符號位 |
unsigned char | short | 0擴展 |
unsigned char | long | 0擴展 |
unsigned char | unsigned short | 0擴展 |
unsigned char | unsigned long | 0擴展 |
unsigned char | float | 轉換到long;然後從long轉換到float |
unsigned char | double | 轉換到long;然後從long轉換到double |
unsigned char | long double | 轉換到long;然後從long轉換到long double |
unsigned short | char | 保留低位字節 |
unsigned short | short | 最高爲作符號位 |
unsigned short | long | 0擴展 |
unsigned short | unsigned char | 保留低位字節 |
unsigned short | unsigned long | 0擴展 |
unsigned short | float | 轉換到long;然後從long轉換到float |
unsigned short | double | 轉換到long;然後從long轉換到double |
unsigned long | long double | 轉換到long;然後從long轉換到long double |
unsigned long | char | 保留低位字節 |
unsigned long | short | 保留低位字節 |
unsigned long | long | 最高位作符號位 |
unsigned long | unsigned char | 保留低位字節 |
unsigned long | unsigned short | 保留低位字節 |
unsigned long | float | 轉換到long;然後從long轉換到float |
unsigned long | double | 直接轉換到double |
unsigned long | long double | 轉換到long;然後從long轉換到long double |