【揭祕】C語言型別轉換時發生了什麼?

技術讓夢想更偉大發表於2020-07-20

ID:技術讓夢想更偉大
作者:李肖遙
連結:https://mp.weixin.qq.com/s/ZFf3imVaJgeesuhl1Kn9sQ

在C語言中,資料型別指的是用於宣告不同型別的變數或函式的一個廣泛的系統,我們常用的算術型別包括兩種型別:整數型別和浮點型別。那麼相互之間具體是怎麼轉化的呢?

瞭解一下型別轉換

不同資料型別的儲存大小和值範圍是不一樣的,程式在初始化的時候就已經設定了,例如:

int a = 9;
float b = 8.5;

a,b佔的位元組大小不一樣,這個我們應該都知道,在C語言中一個表示式允許不同型別的資料進行運算,例如:

int a = 9;
float b = 8.5,c;
c = a + b;

因為計算機硬體在進行算術操作時,要求各運算元的型別具有相同的儲存位數以及一樣的儲存方式,所以就出現了型別轉換。

對於某些型別的轉換,編譯器可以隱式地自動進行,這種轉換稱為自動型別轉換

而有些型別轉換需要程式設計師顯式指明,那麼通常把這種轉換稱為強制型別轉換

自動型別轉換

自動轉換是在源型別和目標型別相容以及目標型別廣於源型別時發生一個型別到另一類的轉換。我們先來看一段程式碼

//vs2019
//來源:技術讓夢想更偉大
//作者:李肖遙
#include <stdio.h>
int main()
{
 //定義一個整型指標變數pPoint
 int* pPoint;

 //定義基本的資料的型別
 char c;
 short s;
 int i;
 long l;
 float f;
 double d;

 //將整型浮點型資料賦值給指標型別
 pPoint = c;
 pPoint = s;
 pPoint = i;
 pPoint = l;
 pPoint = f;
 pPoint = d;
 
 return 0;
}

由於指標變數和整型、浮點這些資料型的型別是不能相互賦值的,編譯報錯輸出:

那麼我們把同型別資料型別進行運算後賦值呢?

//vs2019
//來源:技術讓夢想更偉大
//作者:李肖遙
#include <stdio.h>
int main()
{
 //定義一個整型指標變數pPoint
 int* pPoint;

 //定義基本的資料的型別
 char c;
 short s;
 int i;
 long l;
 float f;
 double d;

 //將整型浮點型資料運算之後賦值給指標型別
 pPoint = c + c;
 pPoint = s + s;
 pPoint = i + i;
 pPoint = l + l;
 pPoint = f + f;
 pPoint = d + d;
 
 return 0;
}
  • char同型別運算,結果是一個int型別。
  • short同型別運算,結果是一個int型別。
  • int同型別運算,結果是一個int型別。
  • long同型別運算,結果是一個long型別。
  • float同型別運算,結果是一個float型別。
  • double同型別運算,結果是一個double型別。

如下圖所示:

同型別運算中:

  • 整型:比int小的,都會轉換成int,比int大的不變。
  • 浮點:不變。

那麼我們把不同型別資料型別進行運算後賦值呢?

//vs2019
//來源:技術讓夢想更偉大
//作者:李肖遙
#include <stdio.h>
int main()
{
 //定義一個整型指標變數pPoint
 int* pPoint;

 //定義基本的資料的型別
 char c;
 short s;
 int i;
 long l;
 float f;
 double d;

 //將整型浮點型資料混合運算賦值給指標型別
 pPoint = c + s;  // char + short = int
 pPoint = c + i;  // char + int = int
 pPoint = c + l;  // char + long = int
 pPoint = c + f;  // char + float = long
 pPoint = c + d;  // char + double = float
 
 return 0;
}
  • char型別與short型別運算,結果是一個int型別。
  • char型別與int型別運算,結果是一個int型別。
  • char型別與long型別運算,結果是一個long型別。
  • char型別與float型別運算,結果是一個float型別。
  • char型別與double型別運算,結果是一個double型別。

結果如下圖所示:

可以得出在不同型別運算中:

  • 如果兩邊均比int小或等於int,那麼結果為int。
  • 如果兩邊有比int大的,那麼結果為比int大的型別。

我們得到結論如圖:

  • 整型型別級別從低到高依次為:
    int -> unsigned int -> long -> unsigned long -> long long -> unsigned long long

  • 浮點型級別從低到高依次為:
    float -> double

自動轉換規則:

  • 圖中橫向箭頭表示必須的轉換,如兩個float型數參加運算,雖然它們型別相同,但仍要先轉成double型再進行運算,結果亦為double型。
  • 圖中縱向箭頭表示當運算子兩邊的運算數為不同型別時的轉換,如一個long 型資料與一個int型資料一起運算,需要先將int型資料轉換為long型, 然後兩者再進行運算,結果為long型。
  • 當較高型別的資料轉換為較低型別時,則可能有些資料丟失。
  • 當較低型別的資料轉換為較高型別時,一般只是形式上有所改變, 而不影響資料的實質內容。
  • 所有這些轉換都是由系統自動進行的,使用時你只需從中瞭解結果的型別即可。

強制型別轉換

強制型別轉換是通過型別轉換運算來實現的。其一般形式為:

(型別說明符) (表示式)

其作用就是把表示式的運算結果強制轉換成型別說明符所表示的型別的值。

//vs2019
//來源:技術讓夢想更偉大
//作者:李肖遙
#include<stdio.h>
#include<string.h>

int main()
{
    float f,x=1.3,y=1.4;
    int i = 4,a,b;
    a = x + y;
    b = (int)(x+y);
    f = 10/i;
    printf("a=%d,b=%d,f=%f,x=%f,y=%f\n",a,b,f,x,y);
}

執行結果如下:

我們從中可以看到,雖然x,y變強制轉換int型,但是最後輸出的值不變,強制型別轉換沒有影響x和y變數原本的型別。而上圖警告已經說明了一切。

注意:在C語言中,對一個變數賦值的時候,這個變數初始定義的型別包含了兩層含義:

  1. 這個資料型別表示的記憶體空間的大小。
  2. 編譯器把設定的數值放到這個記憶體空間,是資料型別的儲存方式解析後存進去的。

總結強調一點

進行強制型別轉換後,記憶體空間裡面的內容是不會發生改變的,改變的是運算時的臨時資料物件的型別,是你去讀取這個記憶體空間時的解析方法。所以,一定要對這個資料型別的記憶體空間和解析方式有一個清晰的認知。

相關文章