【揭秘】C語(yǔ)言類型轉(zhuǎn)換時(shí)發(fā)生了什么?
在C語(yǔ)言中,數(shù)據(jù)類型指的是用于聲明不同類型的變量或函數(shù)的一個(gè)廣泛的系統(tǒng),我們常用的算術(shù)類型包括兩種類型:整數(shù)類型和浮點(diǎn)類型。那么相互之間具體是怎么轉(zhuǎn)化的呢?
了解一下類型轉(zhuǎn)換
不同數(shù)據(jù)類型的存儲(chǔ)大小和值范圍是不一樣的,程序在初始化的時(shí)候就已經(jīng)設(shè)定了,例如:
- int a = 9;
- float b = 8.5;
a,b占的字節(jié)大小不一樣,這個(gè)我們應(yīng)該都知道,在C語(yǔ)言中一個(gè)表達(dá)式允許不同類型的數(shù)據(jù)進(jìn)行運(yùn)算,例如:
- int a = 9;
- float b = 8.5,c;
- c = a + b;
因?yàn)橛?jì)算機(jī)硬件在進(jìn)行算術(shù)操作時(shí),要求各操作數(shù)的類型具有相同的存儲(chǔ)位數(shù)以及一樣的存儲(chǔ)方式,所以就出現(xiàn)了類型轉(zhuǎn)換。
對(duì)于某些類型的轉(zhuǎn)換,編譯器可以隱式地自動(dòng)進(jìn)行,這種轉(zhuǎn)換稱為自動(dòng)類型轉(zhuǎn)換;
而有些類型轉(zhuǎn)換需要程序員顯式指明,那么通常把這種轉(zhuǎn)換稱為強(qiáng)制類型轉(zhuǎn)換。
自動(dòng)類型轉(zhuǎn)換
自動(dòng)轉(zhuǎn)換是在源類型和目標(biāo)類型兼容以及目標(biāo)類型廣于源類型時(shí)發(fā)生一個(gè)類型到另一類的轉(zhuǎn)換。我們先來看一段代碼
- //vs2019
- //來源:技術(shù)讓夢(mèng)想更偉大
- //作者:李肖遙
- #include <stdio.h>
- int main()
- {
- //定義一個(gè)整型指針變量pPoint
- int* pPoint;
- //定義基本的數(shù)據(jù)的類型
- char c;
- short s;
- int i;
- long l;
- float f;
- double d;
- //將整型浮點(diǎn)型數(shù)據(jù)賦值給指針類型
- pPoint = c;
- pPoint = s;
- pPoint = i;
- pPoint = l;
- pPoint = f;
- pPoint = d;
- return 0;
- }
由于指針變量和整型、浮點(diǎn)這些數(shù)據(jù)型的類型是不能相互賦值的,編譯報(bào)錯(cuò)輸出:
那么我們把同類型數(shù)據(jù)類型進(jìn)行運(yùn)算后賦值呢?
- //vs2019
- //來源:技術(shù)讓夢(mèng)想更偉大
- //作者:李肖遙
- #include <stdio.h>
- int main()
- {
- //定義一個(gè)整型指針變量pPoint
- int* pPoint;
- //定義基本的數(shù)據(jù)的類型
- char c;
- short s;
- int i;
- long l;
- float f;
- double d;
- //將整型浮點(diǎn)型數(shù)據(jù)運(yùn)算之后賦值給指針類型
- pPoint = c + c;
- pPoint = s + s;
- pPoint = i + i;
- pPoint = l + l;
- pPoint = f + f;
- pPoint = d + d;
- return 0;
- }
- char同類型運(yùn)算,結(jié)果是一個(gè)int類型。
- short同類型運(yùn)算,結(jié)果是一個(gè)int類型。
- int同類型運(yùn)算,結(jié)果是一個(gè)int類型。
- long同類型運(yùn)算,結(jié)果是一個(gè)long類型。
- float同類型運(yùn)算,結(jié)果是一個(gè)float類型。
- double同類型運(yùn)算,結(jié)果是一個(gè)double類型。
如下圖所示:
同類型運(yùn)算中:
- 整型:比int小的,都會(huì)轉(zhuǎn)換成int,比int大的不變。
- 浮點(diǎn):不變。
那么我們把不同類型數(shù)據(jù)類型進(jìn)行運(yùn)算后賦值呢?
- //vs2019
- //來源:技術(shù)讓夢(mèng)想更偉大
- //作者:李肖遙
- #include <stdio.h>
- int main()
- {
- //定義一個(gè)整型指針變量pPoint
- int* pPoint;
- //定義基本的數(shù)據(jù)的類型
- char c;
- short s;
- int i;
- long l;
- float f;
- double d;
- //將整型浮點(diǎn)型數(shù)據(jù)混合運(yùn)算賦值給指針類型
- pPoint = c + s; // char + short = int
- pPoint = c + i; // char + intint = int
- pPoint = c + l; // char + long = int
- pPoint = c + f; // char + float = long
- pPoint = c + d; // char + double = float
- return 0;
- }
- char類型與short類型運(yùn)算,結(jié)果是一個(gè)int類型。
- char類型與int類型運(yùn)算,結(jié)果是一個(gè)int類型。
- char類型與long類型運(yùn)算,結(jié)果是一個(gè)long類型。
- char類型與float類型運(yùn)算,結(jié)果是一個(gè)float類型。
- char類型與double類型運(yùn)算,結(jié)果是一個(gè)double類型。
結(jié)果如下圖所示:
可以得出在不同類型運(yùn)算中:
- 如果兩邊均比int小或等于int,那么結(jié)果為int。
- 如果兩邊有比int大的,那么結(jié)果為比int大的類型。
我們得到結(jié)論如圖:
- 整型類型級(jí)別從低到高依次為:
int -> unsigned int -> long -> unsigned long -> long long -> unsigned long long
- 浮點(diǎn)型級(jí)別從低到高依次為:
float -> double
自動(dòng)轉(zhuǎn)換規(guī)則:
- 圖中橫向箭頭表示必須的轉(zhuǎn)換,如兩個(gè)float型數(shù)參加運(yùn)算,雖然它們類型相同,但仍要先轉(zhuǎn)成double型再進(jìn)行運(yùn)算,結(jié)果亦為double型。
- 圖中縱向箭頭表示當(dāng)運(yùn)算符兩邊的運(yùn)算數(shù)為不同類型時(shí)的轉(zhuǎn)換,如一個(gè)long 型數(shù)據(jù)與一個(gè)int型數(shù)據(jù)一起運(yùn)算,需要先將int型數(shù)據(jù)轉(zhuǎn)換為long型, 然后兩者再進(jìn)行運(yùn)算,結(jié)果為long型。
- 當(dāng)較高類型的數(shù)據(jù)轉(zhuǎn)換為較低類型時(shí),則可能有些數(shù)據(jù)丟失。
- 當(dāng)較低類型的數(shù)據(jù)轉(zhuǎn)換為較高類型時(shí),一般只是形式上有所改變, 而不影響數(shù)據(jù)的實(shí)質(zhì)內(nèi)容。
- 所有這些轉(zhuǎn)換都是由系統(tǒng)自動(dòng)進(jìn)行的,使用時(shí)你只需從中了解結(jié)果的類型即可。
強(qiáng)制類型轉(zhuǎn)換
強(qiáng)制類型轉(zhuǎn)換是通過類型轉(zhuǎn)換運(yùn)算來實(shí)現(xiàn)的。其一般形式為:
- (類型說明符) (表達(dá)式)
其作用就是把表達(dá)式的運(yùn)算結(jié)果強(qiáng)制轉(zhuǎn)換成類型說明符所表示的類型的值。
- //vs2019
- //來源:技術(shù)讓夢(mèng)想更偉大
- //作者:李肖遙
- #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);
- }
運(yùn)行結(jié)果如下:
我們從中可以看到,雖然x,y變強(qiáng)制轉(zhuǎn)換int型,但是最后輸出的值不變,強(qiáng)制類型轉(zhuǎn)換沒有影響x和y變量原本的類型。而上圖警告已經(jīng)說明了一切。
注意:在C語(yǔ)言中,對(duì)一個(gè)變量賦值的時(shí)候,這個(gè)變量初始定義的類型包含了兩層含義:
- 這個(gè)數(shù)據(jù)類型表示的內(nèi)存空間的大小。
- 編譯器把設(shè)定的數(shù)值放到這個(gè)內(nèi)存空間,是數(shù)據(jù)類型的存儲(chǔ)方式解析后存進(jìn)去的。
總結(jié)強(qiáng)調(diào)一點(diǎn)
進(jìn)行強(qiáng)制類型轉(zhuǎn)換后,內(nèi)存空間里面的內(nèi)容是不會(huì)發(fā)生改變的,改變的是運(yùn)算時(shí)的臨時(shí)數(shù)據(jù)對(duì)象的類型,是你去讀取這個(gè)內(nèi)存空間時(shí)的解析方法。所以,一定要對(duì)這個(gè)數(shù)據(jù)類型的內(nèi)存空間和解析方式有一個(gè)清晰的認(rèn)知。