C++資料型別(強制)轉換詳解

2020-07-16 10:04:35
有時,程式設計的過程中需要將值從一種資料型別轉換為另一種資料型別。C++ 提供了這樣做的方法。

如果將一個浮點值分配給一個 int 整型變數,該變數會接收什麼值?如果一個 int 整數乘以一個 float 浮點數,結果將會是什麼資料型別?如果一個 double 浮點數除以一個 unsigned int 無符號整數會怎麼樣?是否有辦法預測在這些情況下會發生什麼?

答案是肯定的。當運算子的運算元具有不同的資料型別時,C++ 會自動將它們轉換為相同的資料型別。當它這樣做時,遵循一組規則。理解這些規則將有助於程式設計師防止一些細微的錯誤蔓延到自己的程式中。

就像軍隊的軍官有軍階一樣,資料型別也可以按等級排名。如果一個數位資料型別可以容納的數位大於另一個資料型別,那麼它的排名就高於後者。例如,float 型別就超越了 int 型別,而 double 型別又超越了 float 型別。表 1 列出了從高到低排列的資料型別。

表 1 資料型別排名
long double
double
float
unsigned long long int
long long int
unsigned long int
long int
unsigned int
int

表 1 中排名的一個例外是當 int 和 long int 的大小相同時。在這種情況下,unsigned int 將超越 long int,因為它可以儲存更高的值。

當 C++ 使用運算子時,它會努力將運算元轉換為相同的型別。這種隱式或自動的轉換稱為型別強制。當一個值被轉換為更髙的資料型別時,稱之為升級。反之,降級則意味著將其轉換為更低的資料型別。

現在來看一看管理數學表示式評估的具體規則:
  • 規則 1:char、short 和 unsigned short 值自動升級為 int 值。細心的讀者可能已經注意到,char、short 和 unsigned short 都未出現在表 1 中,這是因為無論何時在數學表示式中使用這些資料型別的值,它們都將自動升級為 int 型別。
  • 規則 2:當運算子使用不同資料型別的兩個值時,較低排名的值將被升級為較高排名值的型別。在下面的表示式中,假設 years 是一個 int 變數,而 interestRate 是一個 double 變數:

years * interestRate

在乘法發生之前,years 中的值將升級為 double 型別。
  • 規則 3:當表示式的最終值分配給變數時,它將被轉換為該變數的資料型別。在下面的語句中,假設 area 是一個 long int 長整型變數,而 length 和 width 都是 int 整型變數:

area = length * width;

因為儲存在 length 和 width 中的值是相同的資料型別,所以它們都不會被轉換為任何其他資料型別。但是,乘法的結果將被升級為 long int 型別,這樣才可以儲存到 area 中。

但是,如果接收值的變數的資料型別低於接收的值,那該怎麼辦呢?在這種情況下,值將被降級為變數的型別。如果變數的資料型別沒有足夠的儲存空間來儲存該值,則該值的一部分將丟失,並且該變數可能會收到不準確的結果。

我們知道,如果接收值的變數想要的是一個整數,而賦給它的值是一個浮點數,那麼當轉換為 int 並儲存在變數中時,浮點值將被截斷。這意味著小數點後的所有內容都將被丟棄。範例如下:

int x;
double y = 3.75;
x = y; // x被賦值為3,y仍然保留3.75

但是,重要的是要了解,當變數值的資料型別更改時,它不會影響變數本身。例如,來看下面的程式碼段。

int quantity1 = 6;
double quantity2 = 3.7;
double total;
total = quantity1 + quantity2;

在 C++ 執行上述加法之前,它會將一個 quantity1 值的副本移動到其工作空間中,並將其轉換為 double 型別。然後把 6.0 和 3.7 相加,並且將結果值 9.7 儲存到 total 中。但是,變數 quantity1 保持為 int,儲存在記憶體中的值保持不變,它仍然是整數 6。

型別強制轉換

有時程式設計師想要自己更改值的資料型別,這可以通過使用型別強制轉換表示式來完成。型別強制轉換表示式允許手動升級或降級值。它的一般格式如下:

static_cast<DataType>(Value)

其中 Value 是要轉換的變數或文字值,DataType 是要轉換的目標資料型別。以下是使用型別轉換表示式的程式碼範例:

double number = 3.7;
int val;
val = static_cast<int>(number);

上述程式碼定義了兩個變數:double 型別的 number 和 int 型別的 val。第 3 個語句中的型別轉換表示式返回 number 中的值的副本,轉換為 int。當 double 或 float 型別的值轉換為 int 時,小數部分被截斷,因此該語句將 3 儲存在 val 中。而 number 的值仍為 3.7,保持不變。

型別轉換表示式在 C++ 不能自動執行所需轉換的情況下很有用。

下面的程式顯示了使用型別強制轉換表示式來防止發生整除法的範例。
//This program uses a type cast to avoid an integer division.
#include <iostream>
using namespace std;

int main()
{
    intbooks, months;
    double booksPerMonth;
    // Get user inputs
    cout << "How many books do you plan to read? ";
    cin >> books;
    cout << "How many months will it take you to read them? ";
    cin >> months;
    // Compute and display books read per month
    booksPerMonth = static_cast<double>(books) / months;
    cout << "That is " << booksPerMonth << " books per month.n";
    return 0;
}
程式輸出結果:

How many books do you plan to read? 30
How many months will it take you to read them? 7
That is 4.28571 books per month.

其中,使用型別強制轉換表示式的語句是:

booksPerMonth = static cast<double>(books) / months;

變數 books 是一個整數,但是它的值的副本在除法運算之前被轉換為 double 型別。如果沒有此型別轉換表示式,則將執行整除法,導致錯誤的答案。值得一提的是,如果按以下語句改寫此行,則整除法仍然會發生:

booksPerMonth = static_cast <double> (books / months);

因為括號內的操作在其他操作之前完成,所以除法運算子將對其兩個整數運算元執行整除法,books / month 表示式的結果將是 4,然後將 4 轉換為 double 型別的值 4.0,這就是將賦給 booksPerMonth 的值。

警告,為了防止發生整除法,在除法運算之前,其中一個運算元應該轉換為一個 double 雙精度值。這將強制 C++ 自動將其他運算元的值也轉換為雙精度值。

下面的程式顯示了型別強制轉換的另一種用法:
//This program prints a character from its ASCII code.
#include <iostream>
using namespace std;

int main()
{
    int number = 65;
    //Display the value of the number variable
    cout << number << endl;
    // Use a type cast to display the value of number
    // converted to the char data type
    cout << static_cast<char>(number) << endl;
    return 0;
}
程式輸出結果:

65
A

現在來仔細看一看這個程式。首先,int 變數 number 的值被初始化為值 65,同時將 number 傳送到 cout,導致顯示 65。隨後,型別強制轉換表示式用於將 number 的值轉換為 char 資料型別,再將其傳送到 cout。我們知道,字元作為整數 ASCII 程式碼儲存在記憶體中。因為數位 65 是字母 A 的 ASCII 碼,所以最後的輸出語句會顯示字母 A。

注意,C++ 提供了若干種不同型別的強制轉換表示式。static_cast 是最常用的型別強制轉換表示式,所以這將是在本教學中主要使用的表示式。

C 風格和預標準 C++ 型別強制轉換表示式

雖然 static_cast 是目前使用最多的型別強制轉換表示式,但是 C++ 還支援兩種較舊的形式,這也是程式設計師應該有所了解的,即 C 風格形式和預標準 C++ 形式。

C 風格的轉換將要轉換的資料型別放在括號中,位於值要轉換的運算元的前面。因為型別轉換運算子在運算元前面,所以這種型別轉換表示法被稱為字首表示法,範例如下:

booksPerMonth = (double)books / months;

預標準 C++ 形式型別強制轉換表示式也是將要轉換的資料型別放在其值要轉換的運算元之前,但它將括號放在運算元周圍,而不是圍繞資料型別。這種型別轉換表示法被稱為功能性表示法,範例如下:

booksPerMonth = double(books) / months;