數據型別轉換[C++]

2020-08-10 11:58:48

C++豐富的基本型別允許根據需求選擇不同的基本型別:11種整型和3種浮點型。在處理大量不同情況,尤其是對不同類型進行運算時,存在潛在的混亂。因此,C++支援自動執行很多型別轉換:

  • 將一種算數型別的值賦給另一種算數型別的變數時,C++將對值進行轉換。
  • 表達式中包含不同的型別時,C++將對值進行轉換。
  • 將參數傳遞給函數時,C++將對值進行轉換。

1 初始化和賦值進行的轉換

賦值後值將被轉換爲接收變數的型別。

有些轉換是相對安全的:

  • 將一個值賦給取值範圍更大的型別通常不會導致什麼問題,如short值賦給long變數,只是可能佔用更多位元組而已。
  • 將零賦給bool變數時會轉換成false,將非零值賦給bool變數時會轉換成true。

還有些轉換則會帶來麻煩:

  • 但將一個很大的long值賦給float變數時將降低精度,因爲float只有6位有效數位。
  • 將大浮點型別轉換爲較小的浮點型別,如double值轉換爲float,會降低精度甚至超出目標型別的取值範圍,結果不確定。
  • 將浮點型轉換爲整型,將會導致小數部分消失(截短),甚至超出目標取值範圍,結果不確定(不同系統不一樣)。
  • 將較大的整型轉換爲較小的整型,可能會超出目標型別的取值範圍,通常只複製右邊的位元組。

傳統初始化行爲和賦值相同。

C++11使用大括號{}初始化(即列表初始化)時對型別轉換要求更嚴格。

  • 列表初始化不允許縮窄,即變數的型別可能無法表示賦給它的值,如不允許將浮點型轉換爲整型。
  • 在不同整型之間轉換或將整型轉換爲浮點型可能被允許,條件是編譯器知道目標變數能夠正確地儲存賦給它的值。

2 表達式中的轉換

當同一個表達式中包含兩種不同的算數型別時,有以下情況:

  • 一些型別在出現時自動轉換:在計算表達式時,C++將bool、char、unsigned char、signed char和short值轉換爲int,即整型提升,再將計算結果轉換爲接收變數型別賦給該變數。(int型別爲計算最自然的型別,運算速度可能最快。)
  • 還有一些其他整型提升:若short比int短,則unsigned short型別將被轉換爲int;若兩種型別長度相同,則unsigned short型別將被轉換爲unsigned int。由此確保在對unsigned short進行提升時不會損失數據。
  • 同樣,wchar_t被提升成爲int、unsigned int、long和unsigned long中第一個寬度足夠儲存wchar_t取值範圍的型別。
  • 還有些型別在與其他型別同時出現時將被轉換:不同類型進行運算時,較小型別會轉化爲較大型別。

C++11版本的編譯器校驗表順序:long double,double,float,整型提升。整型提升滿足:

  • 有符號整型級別:long long、long、int、short和signed char。無符號整級別與有符號相同。型別char、unsigned char和signed char的級別相同。wchar_t、char16_t和char32_t的級別與其底層型別相同。
  • 如果兩個運算元都是有符號的或無符號的,低級別的型別轉換爲高級別的。
  • 如果一個有符號,一個無符號且級別高,則將有符號的運算元型別轉換爲無符號運算元所屬型別;如果有符號型別的能表示無符號型別的所有取值,則無符號的運算元型別轉換爲有符號運算元所屬型別;否則,將兩個運算元都轉換爲有符號型別的無符號版本。

3 傳遞參數時的型別轉換

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

  • 可以取消原型對參數轉換的控制,但這樣作並不明智。
  • C++對char和short型別(signed和unsigned)應用整型提升。
  • 爲保證與傳統C的相容性,在將參數傳遞給取消原型對應參數傳遞控制的函數時, C++將float參數提升爲double。

4 強制型別轉換

C++允許通過強制型別轉換機制 機製顯示地進行型別轉換。

int haha = 1;
long haha1 = (long)haha; //來自C語言
long haha2 = long(haha); //純粹的C++
static_cast<long> haha; //haha程式設計long型別

強制型別轉換並不會改變haha變數本身,而是建立一個新的制定型別的值,可以在表達式中使用這個值。C++新格式使強制型別轉換就像是函數呼叫。

C++還引入4個強制型別轉換運算子。

  • static_cast<>可用於將變數本身的值從一種型別轉換爲另一種型別。
  • dynamic_cast<>
  • const_cast<>
  • reinterpret_cast<>

使用強制轉換的原因:

  • 可能有一些值被預設存爲double型別,但要使用它們計算得到一個int型別的值。將兩個double值求和再前值轉換爲int型別,與將兩者先強制轉換成int型別再求和得到的結果很可能是不同的。
  • 使用一種格式的數據能滿足不同的期望。

5 C++11的auto宣告

auto讓編譯器能夠根據初始值的型別推斷變數的型別。

  • auto本是一個C語言關鍵字,但很少使用。
  • 在初始化宣告中若使用auto而不指定變數型別,編譯器吧變數的型別設定成與初始值相同。(容易誤入歧途)
auto n = 100; //int
auto x = 1.5; //double
auto y = 1.3e12L; //long double
auto z = n; //int

處理複雜型別,如標準模組庫(STL)中的型別時,這種自動型別推斷便很有意義。

std::vector<double> scores;
std::vector<double>::iterator pv = scores.begin();
//第二句還可以表達爲
auto pv = scores.begin();