大家都知道,在c/c++中,對於w位編譯器,其有符號數表示的數值範圍為-2 ^ (w-1)~2 ^(w-1)-1,無符號數表示的數值範圍為0 ~ 2 ^ w-1,舉個例子,在16位編譯器中,有符號數的數值範圍為-2 ^ 31 ~ 2 ^ 31-1,無符號數的數值範圍為0 ~ 2 ^ 32-1。那麼,有符號數和無符號數的區別在哪?同樣都是以32位2進製位來表示(後文均以32位為準),為什麼各自表示的數值範圍不同呢,又為什麼是這個範圍呢?
為了解釋上面的問題,就不得不再提到另乙個名詞——「補碼」,什麼是補碼呢?在《深入理解計算機系統》一書中,有這樣一段話:「對於許多應用,我們還希望表示負數值。最常見的有符號數的計算機表示方式就是補碼形式。在這個定義中,將字的最高有效位解釋為負權」,這句話的意思其實很簡單,就是32位二進位制位中,最高位的權重為-1,換句話說,在無符號數中,最高位所代表的值是2 ^ 31,而在有符號數中,其表現方式是補碼形式,最高位所代表的值是- 2^ 31。為了更加形象的來理解這句話的意思,我們用-1來作為乙個例子。
關於這段程式的說明及問題
有一點值得注意的是:通常情況下,數字都預設為有符號型別。因此這裡的int a實際上就是signed int a;可見-1的二進位制位表示為「11111111 11111111 11111111 11111111」。從這32中的最低位開始,每一位分別表示2 ^ 0、2 ^ 1、2 ^ 2、2 ^ 3…2 ^ 30,但是最高位就不一樣了,按照有符號數的補碼形式特點,其最高位的1表示的是負權的-2 ^ 31,這樣,我們把每一位所表示的值加起來就是 - 2 ^ 31 +2 ^ 30+…+2 ^ 1+2 ^ 0=- 2 ^ 31+2 ^ 31-1=-1,可見其剛好就等於-1了,如果我們把程式中的a換成unsigned int型別,那麼按前面所說的,最高位的1就應當表示為2 ^ 31,那麼unsigned int(a)的值就應當是2 ^ 31 +2 ^ 30+…+2 ^ 1+2 ^ 0=2^32-1=4294967295,我們來看看是不是這樣的呢:
可以看到,剛好跟我們想的是一樣的,反過來,如果先定義乙個unsigned 型別的,假設其為2147483649,很明顯,這個數已經超出了有符號數的上限,它的二進位制表示為「10000000 00000000 00000000 00000001」,按照前面分析的,這裡的最高位1表示的是2 ^ 31,把每一位加起來就是2 ^ 31+2^0=2147483649,如果將其轉換為signed型別的話,那麼最高位1表示的就是-2 ^ 31,那麼轉換後的(signed)2147483649就應當為-2 ^ 31+2 ^0=-2147483647,我們來驗證一下:
可以看到,執行結果完全符合我們的猜想。這就說明了有符號數和無符號數的區別:在32位編譯器中,有符號數的二進位制位最高位表示-2^ 31,而無符號數的二進位制位最高位表示的是2^31。根據這一區別,我們也不難得到有符號數與無符號數的一些轉換原理。
前面已經知道了有符號數與無符號數的區別,那麼實際上就很容易得出二者的轉換關係:假設乙個數x,無論它是有符號數還是無符號數,它的二進位制表示肯定都是唯一的(不可能在有符號形式下有一種表示,在無符號形式下也有一種表示),那麼假設其二進位制位中的最高位為m(m=0或1),其餘位組合表示的數為n,打個比方,10的二進位制表示為1010,那麼它的最高位就是m=1,n=2(010),那麼很明顯,x=m*2^(w-1)+n,其中w為這個數的二進位制位數,在32位編譯器中w=32,64位編譯器中w=64。
以32位編譯器為例,對於無符號數,由於其最高位代表2^31,因此x=m * 2 ^ 31+n ;而對於有符號數而言,由於其最高位代表-2 ^31,因此x=-m * 2 ^31+n,因此,無符號數要想轉換為有符號數,就需要減上m * 2 ^32,那什麼時候m為0什麼時候m為1呢?很簡單,對於無符號數來說,m為1表示x>=2 ^31,否則m=0;對於有符號數來說,m=1表示x<0否則m=0。由此得到轉換公式如下:轉換公式如下:
其中u代表無符號數,s代表有符號數,w表示編譯器的位數。
顯示轉換的方式如下所示:
程式不用多說,顯示轉換還是很簡單的,顯示轉換就是一種強制型別轉換。
隱式轉換主要在以下兩種情況下發生:
①當一種型別的表示式被賦值給另外一種型別的變數時;
②當執行乙個運算時,如果它的乙個運算數是有符號的而另乙個是無符號的,那麼就會隱式地將有符號引數強制型別轉換為無符號數。
對於第①種情況,如下所示:
可見,輸出的並不是-1,為什麼不是-1而是4294967295呢?原因就在於unsigned int a=-1;這一句,前面說過
通常情況下,數字都預設為有符號型別。因此這裡的-1就是有符號型別,當它被賦值無符號型變數a時,-1就被隱式轉換為無符號型別了,因此這裡就需要採用前面的轉換公式,-1+2^32=4294967295。
對於第②種情況,如下所示:
如圖所示,a=1,本身是大於-1的,應該返回true,但是由於這裡a為無符號數,-1是有符號數,在進行「>」運算時,-1被強制轉換成了無符號數,即成了4294967295,因此返回的真值是1>4294967295的真值結果,就是false。
這種情況往往對於標準的加減乘除運算來說並沒有多大差異,但是對於「>」、「
根據上面的總結,也能解決為什麼a另一方面,a-b<0雖然也可能引發隱式轉換,但是由於是減法運算,因此一般不會對結果造成影響,它最主要的問題是由於需要作減法運算,因此可能引發資料溢位的問題,比如說int a=-2147483648;int b=100;那麼a
如何理解有符號數和無符號數
這一點,你可能聽過兩種不同的回答。一種是教科書,它會告訴你 計算機用 補碼 表示負數。可是有關 補碼 的概念一說就得一節課,這一些我們需要在第6章中用一章的篇幅講2進製的一切。再者,用 補碼 表示負數,其實一種公式,公式的作用在於告訴你,想得問題的答案,應該如何計算。卻並沒有告訴你為什麼用這個公式就...
有符號數與無符號數
關於有符號數和無符號數的一些重要知識點,包括它們在記憶體中的儲存方式 互相轉換 越界計算等。大家肯定都知道,對於有符號數,資料型別的最高位用於標示資料的符號,最高位為1表示負數,最高位為0表示正數,那麼今天我們主要就此討論乙個問題 在計算機內部具體是如何表示有符號數呢?在計算機內部是通過補碼的方式來...
有符號數和無符號數
有符號和無符號整數 1.通常情況下,大多數字預設的是有符號數,比如 4,5 要想寫乙個無符號數必須在後面加u 比如 4u,5u 2.在計算機中有符號數是用補碼的形式來表示的,最高位是符號位。無符號數就是正數唄 正數的補碼和原碼相同。比如 1 在計算機中表示為 11111111 11111111 11...