C++ Primer Plus--數據處理(三)

介紹C++變量的命名規則,以及數據類型

3.1 簡單變量

int a;
a = 5;

上述語句告訴程序,它正在存儲整數,並使用名稱a來表示該整數的值。實際上,程序將找到一塊能夠存儲整數的內存,將該內存單元標記爲a,並將5複製到該內存單元中,然後,可以在程序中使用a來訪問該內存單元。可以通過&運算符來檢索a的內存地址。

變量名

C++提倡使用有一定含義的變量名,如果表示差旅費,應將其命名爲cost_of_trip或costOfTrip,而不要命名爲a或x等。必須遵循幾種簡單的C++命名規則:

  • 在名稱中只能使用字母字符、數字和下劃線(_);
  • 名稱的第一個字符不能是數字;
  • 區分大小寫
  • 不能將C++關鍵字用作名稱
  • 以兩個下劃線或下劃線和大寫字母開頭的名稱被保留給實現(編譯器及其使用的資源)使用,以一個下劃線開頭的名稱被保留給實現,用作全局標識符;
  • C++對於名稱的長度無限制,名稱中所有的字符都有意義。

最後兩點和前幾點不同,因爲使用_time_stop或_Donut或__time這樣的名稱不會導致編譯器錯誤,而會導致不確定性。即,不知道結果將是什麼,不出現編譯錯誤的原因是,這樣的名稱不是非法的,但是要保留給現實使用。全局名稱指的是名稱被聲明的位置。

命名方案

在給變量命名時,可能在變量名中加入其他信息,即描述變量類型或內容的前綴,例如,可以將整型變量命名myWeight命名爲intMyWeight或nMyWeight,這樣,在閱讀代碼時,一目瞭然,每個變量的意義和類型。常以這種方式使用的前綴用:str或sz(表示以空字符結束的字符串)、b(表示布爾值)、p (表示指針)、c(表示單個字符)。

整型

整型是沒有小數部分的數字,比如:98,-86,0。C++提供了好幾種整型來存儲整數。使用的內存越大,可以表示的整數值範圍也越大。另外,有的類型(符號類型)可以表示正值和負值,而有的類型(無符號類型)不能表示負值。術語寬度用戶描述存儲整數時使用的內存量,使用的內存越多,則越寬。C++的基本整型(按照寬度遞增的順序排序):

  • char:該類型有一些特殊屬性,常用來表示字符,而不是數字
  • short
  • int
  • long
  • long long

計算機內存由一些叫做位(bit)的單元組成。C++中short、int、long和long long類型都是通過使用不同數目的位來存儲值。

在不同的系統中,每種的類型的寬度都不一樣,C++提供了一種靈活的標準,確保了最小長度(從C語言借鑑而來),如下:

  • short至少16位
  • int至少與short一樣長
  • long至少32位,且至少與int一樣長
  • long long至少64位,且至少與long一樣長

實際上short是short int的簡稱,long是long int的簡稱。

位與字節

計算機內存的基本單元時位(bit),字節(byte)通常指的是8位的內存單元。從這個意義上說,字節指的就是描述計算機內存量的度量單位,1KB等於1024字節,1MB等於1024KB。

8位的內存塊可以設置出256種不同的組合,因爲每一位由兩種設置(0和1),所以8位的總組合位:2^8-256。因此8位單元可以表示0-255或-128到127。每增加一位,組合數變加倍。

C++中對字節的定義與此不同,C++字節由至少能夠容納實現的基本字符集的相鄰位組成,也就是說可能取值的數目必須等於或超過字符數目。在美國,基本字符集通過是ASCII和EBCDIC集,它們都可以用8位來容納,所以在使用這兩種字符集的系統中,C++通常包括8位。然而,國際編程可能需要使用更大的字符集,如Uunicode,因此有些實現可能使用16位甚至32位的字符。

C++中檢測類型的長度,sizeof運算符返回類型或變量的長度,單位爲字節。 比如:sizeof(int),或者 對一個變量利用sizeof,如:sizeof n_short (short n_short;)。

在頭文件climits(舊版本limits.h)中包含了關於整型限制的信息。具體地說,它定義了表示各種顯示的符合名稱。比如:INT_MAX 爲int的最大值,CHAR_BIT爲字節的位數。 SHRT_MAX爲short的最大值,LLONG_MAX爲long long的最大值,LONG_MAX爲long的最大值。INT_MIN爲int的最小值。這裏只給出了部分,詳細的可以查看書籍P41。

* 符號常量–預處理方式*

climits文件中包含於下面類似的語句行:

#define INT_MAX 32767

在C++編譯過程中,首先將源代碼傳給預處理器。在這裏,#define和#include一樣,也是一個預處理編譯指令。該編譯指令告訴預處理器:在程序中查找INT_MAX,並將所有的INT_MAX替換爲32767。

初始化

初始化將複製和聲明合併在一起。如下:

int n_int = INT_MAX;

可以將變量初始化爲另一個變量,條件是後者是已經定義過,甚至可以使用表達式來初始化變量,條件是當程序執行到該聲明時,表達式中的所有值都已經定義過:

int uncles = 5;
int aunts = uncles;
int chairs = aunts + uncles + 4;

前面的初始化繼承自C語言,C++還有另一個C語言沒有的初始化語法:

int wrens(432);

注意: 如果不對函數內部定義的變量進行初始化,該變量的值將是不確定的。這意味着該變量的值將是它被創建之前,相應內存單元保存的值。

在變量聲明時對它進行初始化,可避免以後忘記給它賦值的情況發生。

C++11初始化方式

另一種初始化方式,這種方式用戶數組和結構,但在C++98中,也可以用於單值變量:

int hamburgers = {24};

將大括號初始化器用於單值變量的情形不多,但在C++標準使得這種情形更多了。首先,採用這種方式時,可以使用等號(=),也可以不使用:

int emus{7};
int rheas = {12}

其次,大括號可以爲空,即變量被初始化爲零:

int rocs = {};
int psychis{};

無符號類型

前面介紹的4種整數都有一種不能存儲負數值的無符號變體。其優點是可以增大變量能夠存儲的最大值。例如:如果short表示的範圍爲-32768到32767,則無符號版本的表示範圍爲0-65535。當然,僅當數值不會爲負時才應該使用無符號類型,如人口、件數等。創建無符號版本的基本整性,只需要使用關鍵詞unsigned來修改:

unsigned short change;
unsigned long long lang_lang;

注意:unsigned 本身是 unsigned int 的縮寫。

對於一個short變量,取short的最大值(32767),對於符號整型,對最大值加一,則該值將變爲-32768。對於無符號整型,對最大值加一,則該值將變爲:32768。如果將無符號整數0,減一則該值會變成65535。

可以看出,這些整型變量的行爲就像里程錶,如果超越了限制,其值將爲範圍另一端的取值。

選擇整型類型

int被設置爲對目標計算機而言最爲“自然”的長度。自然長度指的是計算機處理起來效率最高的長度。如果沒有其他要求,則應該使用int。

如果知道變量可能表示的整數值大於16位整數的最大可能值,則使用32位。即使系統上int爲32位,也應該這樣。如果存儲的值大於20億,可使用long long。

如果short比int小,則使用short可以節省內存。通常,僅當有大型整型數組時,纔有必要使用short。如果節省內存很重要,則應使用short而不是int,即使它們的長度一樣。例如,如果將程序從int爲16位的系統移植到int爲32的系統,則用戶存儲int數組的內存量將加倍,但short不會受影響。

如果只需要使用一個字節,可使用char。

整型字面量

整型字面量(常量)是顯式地書寫常量,如212或1776。C++能夠以三種不同的計數方式來書寫整型:基數爲10、8和16。如果第一位爲1~9,則基數爲10(十進制);如果第一位爲0,第二位1~7,則基數爲8(八進制);如果前兩位爲0X或0x,則基數爲16(十六進制)。具體進制問題:

在默認情況下,cout以十進制格式顯示整數,而不管這些整數在程序中如何書寫,如:

int waits = 0X42;
cout << waits; 
//輸出結果爲66

這些表達方式僅僅是爲了表達上的方便。例如:如果CGA視頻內存段爲十六進制B000,則不必在程序中使用之前將它轉換爲十進制45056,而只需使用0xB000。但是不管把值書寫爲10、012還是0xA,都將以相同的方式存儲在計算機中—被存儲爲二進制。

如果要以十六進制或八進制方式顯示值,則可以使用cout的一些特殊特性。頭文件iostream提供了控制符endl,用於指示cout重起一行。同樣,它還提供了控制符dec、hex和oct,分別表示用於指示cout以十進制、十六進制和八進制格式顯示整數。

using namespace std;
int chest = 42;
cout << hex;
cout << chest; //輸出2a
cout << oct;
cout << chest; //輸出52

諸如cout<

C++如何確定常量的類型

程序的聲明中將特定的整型變量的類型告訴了C++編譯器,但編譯器是如何確定常量的類型呢?假設在程序中使用一個常量表示一個數字:

cout << "Year = " << 2018 << endl;

程序將1492存儲爲int、long還是其他類型呢?答案是,除非有理由存儲爲其他類型(如使用了特殊的後綴來表示特定的類型,或者值太大,不能存儲爲int),否則C++將整型存儲爲int。

關於後綴,後綴是放在常量後面的字母,用於表示類型。具體如下:

後綴 類型
l或L long常量
ul unsigned long常量
ll或LL long long常量
LU或UL ungigned long常量
ull或Ull或uLL或ULL unsigned long long 常量

對於長度,C++中不同進制,採用存儲整型的規則不同:

進制 存儲類型
十進制 使用後面能過存儲該數的最小類型來表示: int、long 、long long
八進制和十六進制 使用後面幾種類型中能過存儲該數的最小類型來表示: int、unsigned int、long、unsigned long、long long 、unsigned long long

十六進制數0x9C40(40000)將被表示爲unsigned int,這是因爲十六進制常用來表示內存地址,而內存地址沒有符號。

char類型:字符和小整數

char類型是專門爲存儲字符而設計的。編程語言通過使用字母的數值編碼來存儲字符。因此char類型是另一種整型。它足夠長,能過表示計算機系統中的所有字符—字母、數字、標點符號等等。實際上,很多系統支持的字符不操作128個,因此用一個字節就可以表示所有的符號。雖然,char最常用來處理字符,但也可以將它用做比short更小的整型。

在美國,最常用的符號集是ASCII字符集。例如,字符A的編碼是65,字母M的編碼爲77。

char ch;
cout << "Enter a chararcter: " << endl;
cin >> ch;
cout << "Thank you for the " << ch << " character" << endl;

輸入M,結果輸出爲 Thank you for the M character.程序打印的是M,而不是77。通過查看內存可知,77是存儲在變量ch中的值。這種神奇的力量來自cin和cout,而不是char,這些工具完成了轉換工作。輸入時,cin將鍵盤輸入的M轉換爲77;輸出是cout將77轉換爲M。

如果將77存儲在int變量中,則cout將把它顯示爲77(也就是說cout顯示兩個字符7)。C++中書寫字符字面量:將字符用單引號括起來。如’M’。(注意:C++對字符用單引號對字符串使用雙引號,這兩者差別比較大)。cout引入一項新特性–cout.put()函數,該函數顯示一個字符。

char ch = 'M'; 
int i = ch;
cout << i; //結果爲77
ch = ch + 1;
i = ch;
cout << i //結果爲78
cout.put(ch); //結果爲N

上面程序中,ch存儲的實際上是整數,因此可以對其使用整數操作,如加一。

char ch;
cin >> ch; //輸入5,實際上ch存儲的整數53(5的ASCII編碼)

上述代碼將讀取字符“5”.並將其對應的字符編碼存儲到ch變量中。

int n;
cin >> n; //輸入5

上述代碼獲取字符“5”,並將其轉換爲對應的數字5,並存儲到n變量中。

成員函數cout.put()

cout.put()成員函數提供了一種顯示字符的方法,可以代替<<運算符。cout.put存在的必要性:在c++的Release2.0之前,cout將字符變量顯示爲字符,而將字符常量(如‘M’和‘N’)顯示爲數字。問題是,C++早期版本將字符常量存儲爲int類型。也就是說,‘M’的編碼將被存儲在一個16或32爲單元中。而char變量一般佔8位。下面的語句從常量“M”中賦值左邊的8位到變ch中:

char ch = 'M'

遺憾的是,對於cout來說,‘M’和ch看上去有天壤之別,雖然存儲的值一樣。下面的語句將打印字符M的ASCII碼,而不是字符M:

cout << 'M';

但是下面打印字符M:

cout.put('M');

C++Release2.0之後,將字符常量存儲位char類型,而不是int,意味着cout現在可以正確處理字符常量。

char字面值

在C++中,書寫字符常量的方式有多種,對於常規字符(字母,數字和標點符號),最簡單的方法是將字符用單引號括起來。這種表示法代表的是字符的數字編碼。例如,ASCII系統中的對應情況如下:

  • ‘A’爲65,即字符A的ASCII
  • ‘a’爲97
  • ‘0’爲48
  • ’ ‘爲32
  • ‘!’爲33

這種表示法優於數值編碼,更加清晰,而不需要知道編碼方。如果系統使用的是EBCDIC,則A的編碼值不是65,但’A‘表示的仍然是字符A。

轉義字符: 有些字符不能之間通過鍵盤輸入到程序中,比如:回車等。C++提供了一種特殊的表示方法–轉義字符。例如:\”將雙引號作爲常規字符,\t表示水平製表符等等。

將轉移字符作爲字符常量時,應用單引號括起來;將他放在字符串中不要使用單引號。

基於字符八進制和十六進制編碼來使用轉義字符。例如,Ctrl+Z的ASCII碼爲26,對應的八進制編碼爲032,十六進制編碼爲0X1a。可以使用下面的轉義字符來表示該字符: \032或\x1a。

通用字符名

通用字符名的用法類似於轉義序列。通用字符名可以以\u或\U開頭。\u後面是8個十六進制位,\U後面則是16個八進制位。這些位表示的是字符的ISO 10646碼點。(ISO 10646是一種正在制定的國際標準,爲大量的字符提供了數字編碼)。

#include <iostream>
using namespace std;

int main()
{
    cout << "Let them eat g\u00E2teau.\n";
    return 0;
}

輸出爲:Let them eat gâteau.

Unicode提供了一種表示各種字符集的解決方案—爲大量字符和符號提供標準數值編碼,並根據類型給他們分類。例如:ASCII碼爲Unicode的子集,因此在這兩種系統中,美國的拉丁字母(如A和Z)表示相同。然後,Unicode還包含其他拉丁字符。

Unicode給每個字符制定一個編號–碼點。Unicode碼點通常類似於:U-222B。其中U表示這是一個Unicode字符,而222B是該字符的十六進制編碼。

國際標準組織(ISO)建立了一個工作組,專門開發ISO 10646—這也是對一個多語言文本進行編碼的標準。ISO 10646小組和Unicode小組從1991年開始合租,以確保他們的同步。

signed 和 unsigned char

與int不同的是,char默認情況下既不是沒有符號,也不是有符號。是否有符號由C++決定。

char fodo //可能爲有符號,也可能無符號
unsigned char bar //無符號
signed char snark //有符號

如果char作爲數值類型,unsigned char類型表示的範圍爲0~255,而signed char表示的範圍爲-128~127。如果使用char變量存儲200這樣大的值,在某些系統上可以,而在另一些系統上可能不可以。但是使用unsigned char可以在任何系統上達到這種目的。如果使用char存儲ASCII字符,則有沒有字符都沒關係。

wchar_t

wchar_t(寬字符類型)可以表示擴展字符集。wchar_t類型是一種整數類型,它有足夠的空間,可以表示系統使用的最大擴展字符集。這種類型與另一種整型(底層(underlying)類型)的長度和字符屬性相同,對底層系統的選擇取決於實現,因此在一個系統中,他可能是unsiged short,而在另一個系統中,則可能是int。

cin和cout將輸入和輸出看作是char流,因此不適於用來處理wchar_t類型。iostream頭文件的最新版提供了類似的工具—wcin和wcout,可用於處理wchar_t。另外,可以通過加上前綴L來表示寬字符常量和寬字符串。

wchar_t bob = L'P';
wcout << L"tall" << bob << endl;

本書不使用寬字符類型,但應知道這種類型,尤其是在進行國際編程或使用Unicode或ISO 10646時。

C++11新增類型 char16_t和char32_t

隨着編程人員的日益熟悉Unicode,類型wchar_t顯然不再滿足需求。事實上,在計算機系統上驚喜字符和字符串編碼時,僅使用Unicode碼點並不夠。具體說,進行字符串編碼時,如果由特定長度和符號特徵的類型,將很有幫助,而類型wchar_t的長度和符號特徵隨實現而已。因此,C++11新增了char16_t和char32_t,兩者都無符號,前者長爲16爲,後者長爲32爲。使用前綴u表示char16_t字符常量和字符串常量,如u’be goog’;使用前綴U表示char32_t常量,如:U’R’。類型char16_t與/u00F6形式的通用字符名匹配,而類型char32_t與/U0000222B形式的通用字符名匹配。

char16_t ch1 = u'q';
char32_t ch2 = U'\U0000222B';

bool類型

在計算中,布爾變量的值可以時true或false。

bool is_ready = true;

字面值true和false都可以通過提升轉換爲int類型,true被轉換爲1,false被轉換爲0。任何非零值可以轉換爲true,而零被轉換爲false。

bool start = -100;
bool end = 0;

3.2 const限定符

使用關鍵字const來修改變量聲明和初始化,例如,假設需要一個表示一年中月份數的符號常量:

const int Months =12;

這樣,便可以在程序中使用Months,而不是12了。常量(如Months)被初始化後,其值就被固定了,編譯器將不允許在修改該常量的值。如果這樣做,g++將指出程序視圖給一個只讀變量賦值。const被叫做限定符,因爲它限定了聲明的含義。

一種常見的做法是將名稱的首字母大寫,以提醒Months是一個常量。

const比#define好,首先,它能明確指定類型;其次,可以使用C++的作用域規則將定義限制在特定的函數或文件中;最後,const用戶更復雜的類型,後面介紹。

建議使用const而不是#define。

3.3 浮點數

對於浮點數,計算機將其分爲兩部分存儲。一部分表示值,另一部分用於對值進行放大或縮小。比如:對於數字34.1245和34124.5,它們處理小數點位置不同外,其他都相同。可以把第一個數表示爲0.341245(基準值)和100(縮放因子),而將第二個表表示爲0.341245(相同基準值)和100(縮放因子更大)。縮放因子的作用是移動小數點的位置,術語浮點因此而得名。C++內部表示浮點數的方法與此相同,只不過是二進制,因此縮放因子是2的冪,不是10的冪。

3.3.1 書寫浮點數

C++有兩種書寫浮點數的方式:

  • 第一種使用常用的標準小數點表示法:12.34
  • 第二種E表示法: 3.45E6指的是3.45與1000000相乘的結果;8.33E-4, 7E5,-8.33E4。

E表示法適合表示非常大和非常小的數。E表示法確保數字以浮點數格式存儲,即使沒有小數點。注意,既可以使用E也可以使用e,指數可以是正數也可使負數。數字中不能有空格,比如:7.2 E6是非法的。

指數爲負數意味着除以10的乘方,而不是乘以10的乘方。因此8.33E-4表示8.33/104 ,即0.000833。數值前面的符號用於數值,而指數的符號用戶縮放。

3.3.2 浮點類型

C++三種浮點類型:float、double和long double.這些類型是按照它們可以表示的有效位數和允許的指數最小範圍來描述的。有效位數是數字中有意義的位。例如:14179英尺,使用了5個有效位;13000英尺,使用了2個有效位,其他3位爲佔位符;1.234,使用了4個有效位。

C++對有效位數的要求是,float至少32位;double至少48位,且不少於float;long double至少跟double一樣多。通常,float位32位,double爲64位,long double爲80、96或128位。另外三種類型的指數範圍至少是-37至37。

#include <iostream>
using namespace std;

int main()
{
        cout.setf(ios_base::fixed, ios_base::floatfield);
        float tub = 10.0 / 3.0;
        const float million = 1.0e6;
        double mint = 10.0 / 3.0;
        cout << "tub = " << tub <<endl;
        cout << "tubs = " << tub * million << endl;
        cout << "mint = " << mint << endl;
        cout << "mints = " << mint * million << endl;
        return 0;
}

結果:
tub = 3.333333
tubs = 3333333.250000
mint = 3.333333
mints = 3333333.333333

通常cout會刪除結尾的零,例如,將3333333.250000顯示爲 3333333.25。調用cousetf()將覆蓋這種行爲。tub和mint都被初始化爲10.0/3.0=3.333333333333….,由於cout打印6位小數,因此tub和mint都是精確的。但是當程序將每個數乘以一百萬後,tub在第7個3之後就不正確的值有了誤差。然後,double類型的變量顯示了13個3,因此它至少有13位精確。這是由於float的精度限制。

讀取包含文件:程序中的所有文件都存在於計算機中,或位於計算機可以使用的地方。找到使用的包含文件,看看它們包含的內容,很快發現,源文件和頭文件都是知識和信息的很好來源。

浮點常量

與整型相比,浮點數優點:

  • 可以表示整數之間的值
  • 由於有縮放因子,可以表示的範圍大得多

浮點數缺點:

  • 浮點運算的速度通常比整數運算慢
  • 精度將降低

fltadd.cpp程序:

#include <iostream>
using namespace std;

int main()
{
        float a = 2.34e22;
        float b = a +  1.0;

        cout << "a = " << a << endl;
        cout << "a - b = " << b -a << endl;
        return 0;
}

結果: a = 2.34e+22
a - b = 0

問題在於,2.34e22是一個小數點左邊有23位的數字。加上1,就是在第23位加1。但是float類型只能表示數字中的前6或前7位,因此修改第23位對這個值不會有影響。

3.4 C++算術運算符

C++中常用的運算符:

  • +運算對操作數執行加法
  • -運算
  • *運算
  • /運算
  • %運算符求模,生成第一個數除以第二個數後的餘數。例如19%6=1。如果其中一個是負數,則結果的符號滿足如下規則:(a/b)*b+a%b = a,%的操作數必須是整數。

arith.cpp

#include <iostream>
using namespace std;

int main()
{
        float a = 10.23;
        float b = 11.22;
        cout.setf(ios_base::fixed, ios_base::floatfield);

        cout << "a = "<<  a <<endl;
        cout << "a + b = " <<  a + b << endl;
        return 0;
}

結果:a = 10.230000
a + b = 21.450001

這是由於float保證6位有效位。

3.4.1 運算符優先級和結合性

先乘除,後加減

*、/和%的優先級相同

float logs = 120 / 4* 5;

對於上式,運算符/和 的優先級相同,因此優先級本身不能指出程序究竟是先計算120除以4,還是先計算4*5。兩種結果截然不同。

當兩個運算符優先級相同時,C++將看操作數的結合性是從左到右還是從右到左。從左到右意味着如果兩個優先級相同的運算符被同時用於一個操作數,則首先應用左側的運算符。查表得,乘除是從左到右結合得,所以上述式子應先計算120/4,得到結果30再除以5。

3.4.2 除法分支

除法運算符(/)的行爲取決於操作數的類型。如果兩個操作數都是整數,則C++將執行整數除法,這意味着小數部分將被丟棄,使得最後的結果是一個整數。如果其中有一個(或兩個)操作數是浮點數,則小數部分保留,結果爲浮點數。

除法運算符表示了3種不同的運算:int除法、float除法、double除法。C++根據上下文來確定運算符的含義,使用相同的符號進行多種操作叫做運算符重載。

3.4.3 求模運算符

求模運算符返回整數除法的餘數,它與整數除法先結合,尤其適用於解決要求將一個量分成不同的整數單元的問題,例如:英寸轉換爲英尺和英寸。

將181鎊,轉換爲英石和鎊。一英石等於14磅.

#include <iostream>
using namespace std;

int main()
{
        const int lbs_per_stn = 14;

        int lbs = 181;
        int stone = lbs / lbs_per_stn;
        int pounds = lbs % lbs_per_stn;
        cout << lbs << " pounds are " << stone << " stone, "
        <<  pounds << " pound(s)."<< endl;
        return 0;
}

結果:181 pounds are 12 stone, 13 pound(s).

3.4.4 類型轉換

C++自動執行類型轉換:

  • 將一個算術類型的值賦給另一種算術類型的變量
  • 表達式種包含不同類型
  • 將參數傳遞給函數

初始化和賦值進行的轉換

C++允許將一種類型的值賦給另一種類型的變量。值將被轉換爲接受變量的類型。假設so_long的類型爲long,thirty的類型爲short,而程序中有:

so_long = short

則進行賦值時,程序將thirty的值(short通常爲16位)擴展爲long值(通常32位)。擴展後將得到一個新值,這個值存儲再so_long中,而thirty的內容不變。

將一個值賦給取值範圍更大的類型通常不會導致問題。例如,將short值賦給long變量並不會改變值,只是佔位符的字節更多而已。

然而,建一個很大的long(如2111222333)值賦給float的變量將降低精度。因爲float只有6位有效數字,因此這個值將被四捨五入爲2.11122E9。因此,有些轉換是不安全的。

潛在的數值轉換問題:

  • 將較大的整數轉換爲較小的整型,如將long轉換爲short,原來的值可能超出目標類型的取值範圍,通常只複製右邊的字節;
  • 將浮點數轉換爲整型,小數部分丟失(不是四捨五入),原來的值可能超出目標類型的取值範圍,在這種情況下,結果可能不確定;
  • 將較大的浮點類型轉換位較小的浮點類型,如將double轉換爲float,精度(有效位位數)降低,,原來的值可能超出目標類型的取值範圍,在這種情況下,結果可能不確定;

將0賦值給bool變量,將被轉換爲false;而非零將被轉換爲true。

以{}方式初始化時進行的轉化(C++11)

C++將使用大括號的初始化稱爲列表初始化,因爲這種初始化常用於給複雜的數據類型提供值列表。對類型的轉化要求更嚴格。具體,列表初始化不允許縮窄,即變量的類型可能無法表示賦給它的值。例如,不允許浮點數轉換爲整型。在不同的整型之間轉換或將整型轉換爲浮點型可能被允許。例如:可見long變量初始化爲int類型的值,因爲long總是至少與int一樣長;相反轉換也可能被允許,只要int變量能夠存儲給它的long常量。

表達式中的轉換

在計算表達式時,C++將bool、char、unsigned char、signed char和short值轉換爲int。具體地說,true被轉換爲1,false被轉換爲0,這些轉換稱爲整型提升。

整型提升還包括:如果short比int短,則unsigned short類型轉換爲int;如果兩種類型的長度相同,則unsigned short類型轉換爲unsigned int。這種規則保證對unsigned short提升時不會損失數據。

將不同類型進行算術運算時,也會進行一些轉換。比如將int和float相加。當運算涉及兩種類型時,較小的類型被轉換爲較大的類型。編譯器通過校驗表來確定算術表達式中執行的轉換,校驗表如下:

  • 如果有一個操作數的類型爲long double,則將另一個操作數轉換爲long double;
  • 否則,如果有一個操作數的類型爲double,則將另一個操作數轉換爲double;
  • 否則,如果有一個操作數的類型爲float,則將另一個操作數轉換爲float;
  • 否則,說明操作數都是整型,因此執行整型提升;
  • 在這種情況下,如果兩個操作數都是有符號或無符號的,且其中一個操作數的級別比另一個低,則轉換爲高級別的類型;
  • 如果一個操作數有符號,另一個操作數無符號,且無符號操作數的級別比有符號操作數的級別高,則將有符號操作數轉換爲無符號的操作數類型;
  • 否則,如果有符號類型可表示無符號類型的所以可能值,則將無符號類型轉換爲有符號操作數所屬的類型;
  • 否則,將兩個操作數都轉換爲無符號版本。

參數傳遞的轉換

傳遞參數時的類型轉換通常由C++函數原型控制。

強制類型轉換

C++允許通過強制轉換機制顯示地進行類型轉換。強制類型轉換格式有兩種,例如:爲將存儲在變量thorn中的int值轉換爲long類型,如下:

(long)thorn//來自C
long(thorn)//C++新格式:像函數調用一樣

強制轉換不會改變thorn本身,而是創建一個新的、指定類型的值。

C++還引入了4個強制類型轉換符,對他們的使用要求更嚴格。後面介紹,在這四種運算符中,static_cast<>可用於將一種數值轉換爲另一個種數值類型,例如將thorn轉換爲long類型:

static_cast<long> (thorn)

推廣之,可以這樣做:

static_cast<typename> (value)

typecast.cpp

#include <iostream>
using namespace std;

int main()
{
        int auks, bats, coots;
        auks = 11.99 + 19.99; //相加賦值給int變量,被截斷爲31,

        bats = int(11.99) + int(19.99);//先截斷,在相加
        coots = (int) 11.99 + (int) 19.99;
        cout << "auks = " << auks << ", bats = " << "bats"
        << ", coots = " << coots<< endl;

        char ch = 'Z';
        cout << "The code for " << ch <<  " is "
        << int(ch) << endl;
        cout << "Yes, the code is " << static_cast<int>(ch) << endl;
        return 0;
}

auks = 31, bats = bats, coots = 30
The code for Z is 90
Yes, the code is 90

3.4.5 C++11中的auto聲明

C++新增了一個工具,讓編譯器能夠根據初始值的類型推斷變量的類型。爲此,它重新定義了auto的含義。auto是C語言的關鍵子,當很少使用。在初始化聲明中,如果使用關鍵字auto,而不指定變量類型,編譯器將把變量的類型設置成與初始值相同:

auto n = 100; //n是整型
auto x = 1.5 // x is double
auto y = 1.3e12L // y is long double 

然而,自動推斷類型並非爲這種簡單情況而設計;事實上,如果將其用於這種簡單情形,甚至可能讓您誤入歧途。例如,假設要將x、y、z都指定爲double,並編寫了如下代碼:

auto x = 0.0; //浮點型
double y = 0; //浮點型
auto z = 0; //整型

處理複雜類型,如標準模塊庫(STL)中的類型,自動類型推斷的優勢才能顯現出來。例如,對於下述C++98代碼:

std:vector<double> scores;
std:vector<double>::iterator pv = scores.begin();

C++允許您將其重寫爲:

std::vector<doble> scores;
auto pv = scores.begin()

3.5 總結

C++的基本類型分爲兩組:

  • 由存儲爲整型的值組成
  • 由存儲爲浮點格式的值組成

整型通過存儲值時的內存量及有無符號來區分。整型從最小到最大依次是:

bool \ char \ signed char \ unsigned char \ short \ unsigned short \ int \ unsigned int \ long \ unsigned long \ long long \ unsigned long lon

3種浮點類型:

float \ double \ long double

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章