天天看點

變量和基本類型

帶符号和無符号類型

除去布爾型和擴充的字元型之外,其他整型可以劃分為帶符号的和無符号的兩種。帶符号類型可以表示正數、負數和0,無符号類型則僅能表示大于等于0的值。

類型int、short、long和long long都是帶符号的,通過在這些類型名前添加unsigned就可以得到無符号類型,例如unsigned long。類型unsigned int可以編寫為unsigned。

與其他整型不同,字元型被分為了三種:char、signed char和unsigned char。特别需要注意的是:類型char和類型signed char并不一樣。盡管字元型有三種,但是字元的表現形式卻隻有兩種:帶符号的和無符号的。類型char實際上會表現為上述兩種形式中的一種,具體是哪種由編譯器來決定。

如何選擇類型

和c語言一樣,c++的設計準則之一也是盡可能地接近硬體。c++的算術類型必要滿足各種硬體特質,是以它們常常顯得繁雜而令人不知所措。事實上,大多數程式員能夠對資料類型的使用做出限定進而簡化選擇的過程。以下是一些經驗準則:

當明确知道數值不可能為負時,選用無符号類型。

使用int執行整數運算。在實際應用中,short常常顯得太小而long一般和int有一樣的尺寸。如果你的數值超過了int的表示範圍,選用long long。

在算術表達式中不要還有char或bool,隻有在存放字元或布爾值時才使用它們。因為類型char在一些機器上是有符号的,而在另一些機器上又是無符号的,是以如果使用char進行運算特别容易出問題。如果你需要使用一個不大的整數,那麼明确指定它的類型是signed char或者unsigned char。

執行浮點數運算選用double,這是因為float通常精度不夠用而雙精度浮點數和單精度浮點數的計算代價相差無幾。事實上,對于某些機器來說,雙精度運算甚至比單精度還快。long double提供的精度在一般情況下是沒有必要的,況且它帶來的運作時消耗也不容忽視。

 類型的轉換

類型所能表示的值的範圍決定了轉換的過程:

當我們把一個非布爾型的算術值賦給布爾類型時,初始值0則結果是false,否則結果為true。例如:bool b=42;

當我們把一個布爾型值賦給一個非布爾型時,初始值為false則結果是0,初始值為true則結果為1.

當我們把一個浮點數賦給整型類型時,進行了近似處理。結果值将僅保留浮點數中小數點之前的部分。

當我們把一個整數值賦給浮點類型時,小數部分記為0。如果該整數所占的空間超過了浮點類型的容量,精度可能有損失。

當我們賦給無符号類型一個超過它表示範圍的值時,結果是初始值對無符号類型表示數值總數取模後的餘數。例如,8比特大小的unsigned char可以表示0至255區間内的值,如果我們賦了一個區間以外的值,則實際的結果是該值對256取模後所得的餘數。是以,将-1賦給8比特的unsigned char 所得的結果是255.

當我們賦給帶符号類型一個超出它表示範圍的值時,結果是未定義的。此時,程式可能繼續工作、可能崩潰,也可能生成垃圾資料。

含有無符号類型的表達式

盡管我們不會故意給無符号對象賦一個負值,卻可能寫出這麼做的代碼。

例如,當一個算術表達式中既有無符号數又有int值時,那個int值就會轉換為無符号數。把int轉換為無符号數的過程和把int直接覆給無符号變量一樣:

unsigned u=10;

int i=-42;

cout<<i+i<<endl;  //輸出-84

cout<<u+i<<endl; //如果int占32位,輸出4294967264

在第一個輸出表達式裡,兩個(負)整數相加并得到了期望的結果。在第二個輸出表達式裡,相加前首先把整數-42轉換為無符号數。把負數轉換為無符号數類似于直接給無符号數賦一個負值,結果等于這個負數加上無符号數的模。

當從無符号數中減去一個值時,不過這個值是不是無符号的數,我們都必須確定結果不能是一個負值。

如果表達式裡既有帶符号類型又有無符号類型,當帶符号類型取值為負時會出現異常結果,這是因為帶符号數會自動轉換為無符号數。例如,在一個形如”a*b"的式子中,如果a=-1,b=1,而且a是int,b是unsigned,則結果須視在目前機器上int所占位數而定。