首先明確一下這裡所說的數值常量指的是程式中的乙個數字,比如:
if(1
<2)
其中1
、2
就是數值常量。
就以數字1
為例,1
在很多態別的表示範圍之內,比如short
、int
、unsigned int
等,那麼編譯器會將1
解讀成哪個型別呢?這是由c標準規定的,對於不同版本的c標準,相關規定的具體內容有所差異,對於c90,相關規定如下表所示:
範圍型別
0~231-1
int231~232-1
unsigned int
232~263-1
long long
263~264-1
unsigned long long
範圍型別
0~231-1
int231~263-1
long long
263~264-1
unsigned long long
細心的同學可能會發現,上表中沒有給出負值的情況,比如-10
。編譯器在遇到負值的時候,先不看符號,而是根據數字來確定型別,然後再處理負號。仍舊拿-10
打比方,編譯器根據10
來確定型別為int
,然後再處理負號。
為什麼要強調數值常量的型別呢?因為這裡面有一些陷阱需要注意。以c90標準來說,考慮如下的表示式:
-
2147483648
<
2147483647
很多人第一反應都是這個表示式為true
,畢竟從數值上看這是顯然的。但是,支援c90標準的編譯器可不這麼認為!關鍵是-2147483648
,編譯器根據2147483648
也就是231,確定這個數值的型別為unsigned int
。再考慮負號,根據負數的補碼的轉換規則:對應正數(絕對值)按位取反再加1:
8000_0000 按位取反⇒ 7fff_ffff 再加1⇒ 8000_0000
就這樣,編譯器把-2147483648
硬是給處理成了unsigned int
型別的2147483648
,而2147483648
是大於2147483647
的。但是編譯器又不能把2147483648
解讀成int
型別,因為補碼表示是不對稱的,int
型別最小可以表示到-2147483648
,但最大只能表示到2147483647
。如果能把2147483648
表示成更大的有符號型別比如long long
就不會有上述問題了,c99標準正是這麼做的。不過為了寫出不同版本的標準下,行為一致的程式,我們還是要注意這個細節。
為了加深理解,不妨再來看幾個例子(仍然根據c90標準):
例1
int i =
-2147483648;if
(i <
2147483647
)
此時,會列印出-2147483648 < 2147483647。上文已說過,編譯器會把-2147483648
解讀成一串二進位制0x8000_0000 ,因此變數i所在記憶體儲存的也是這一串二進位制,但不同的是,因為i是int
型別,因此會以int
來看待這串二進位制,乙個負數自然是小於2147483647的。
例2
-
2147483647-1
<
2147483647
對於-2147483647
,編譯器根據2147483647
確定其為int
型別,然後處理負號:
7fff_ffff 按位取反⇒ 8000_0000 再加1⇒ 8000_0001
-2147483647 - 1
則得到8000_0001 - 1 = 8000_0000
,由於是按int
型別來看,因此8000_0000
是乙個負數,且是int
所能表達的最小負數-2147483648
。所以例2的表示式為true
。值得一提的是,int_min通常就定義為:
#define int_min (-2147483647 - 1)
這樣一來,這個巨集不管在c90還是c99標準都能工作的很好。
例3
if(-
2147483648-1
==2147483647
)
編譯器會將-2147483648
解讀成unsigned int
型別的二進位制串8000_0000
,而8000_0000 - 1 = 7fff_ffff
,因此例3中條件成立,會執行printf語句。
除了讓編譯器自己去解讀數值常量的型別,我們還可以通過在數值常量後面加上字尾來主動告訴編譯器數值常量的型別。比如0u
或0u
就是告訴編譯器,這是乙個unsigned int
的0
。此外,也可以用強制型別轉換來實現這一目標,比如(unsigned)0
。
值得關注的是,當無符號數和有符號數一起運算時,c語言會進行型別提公升,把有符號數按照無符號數看待。不同型別的數混在一起運算時,有一些值得注意的地方,如下表:
關係表示式
型別結果
說明0 == 0u
無符號true
0000_0000 == 0000_0000
-1 < 0
有符號true
-1 < 0
-1 < 0u
無符號
false
ffff_ffff > 0000_0000
2147483647 > -2147483647 - 1
有符號true
231-1 > -231
2147483647u > -2147483647 - 1
無符號
false
231-1 < 231
2147483647 > (int)2147483648u
有符號
true
231-1 > -231
-1 > -2
有符號true
-1 > -2
(unsigned)-1 > -2
無符號true
231-1 > 231-2
[1] 南大袁春風教授的計算機系統基礎課程
計算機系統基礎
includeint main return 0 如果將表示式換成 2147483647 1 2147483647 結果又會怎麼樣呢 編譯器如何處理字面量 高階語言中運算規則 高階語言與指令之間的對應 機器指令的執行過程 機器級資料的表示和運算 sum int a unsigned int len ...
計算機系統基礎摘記 整數在計算機中的表示
2 整數在計算機中的表示 參考文獻 計算機是使用二進位制來表示資訊,因為對於電路來說,表示1和0兩個狀態是非常容易實現的。若要使用二進位制來表示數值,則需要規定二進位制對數值進行編碼的規則,不同編碼規則下,同一串二進位制表示的數值可能不同。下面介紹幾種常見的整數編碼方式。原碼最容易理解,對於有符號數...
計算機系統概論基礎
1 第一代計算機採用的是電子管 第二代計算機採用的是電晶體 第三代計算機採用的是中小規模積體電路 計算機採用的是大規模 超大規模積體電路。2 計算機系統有硬體系統和軟體系統構成 3 計算機系統的三個層次結構由內到外分別是硬體系統 軟體系統和應用軟體。在硬體之外的所有層次統稱為虛擬機器。4 cpu 儲...