C的隱式型別轉換

2021-07-30 06:02:30 字數 2758 閱讀 7616

這篇文章僅僅針對c語言存在的隱式型別轉換做一些分析,關於c++的這方面研究,有時間我再另外寫一篇文章。

關於隱式型別轉換,是指發生在沒有明確說明的情況下(c語言風格的強制型別轉換就是屬於我們程式設計師有明確說明的),編譯器自動幫我們執行的型別轉換。

通常同型別的資料進行運算、比較和賦值的時候我們是不需要擔心的,這裡我只是說明不同型別的資料進行運算、比較和賦值時,且我們程式設計師沒有指定型別轉換時,編譯器是如何幫我們進行處理型別之間的轉換的,只有知道這個過程,才能讓我們知道程式設計時應該注意和避免的地方。

想要知道隱式型別轉換,我們有必要了解一下整型提公升(integer promotion),這也是屬於隱式型別轉換的一種方式。

整型提公升是c程式語言中的一項規定:在表示式計算時(包括比較運算和算術運算等),比int型別小的型別(char, signed char, unsigned char, short, unsigned short等)首先要提公升為int型別,然後再執行表示式的運算。

具體的我們從下面的程式進行分析吧

#include 

int main()

執行結果我想很多人都可以想到是:a但是編譯器是怎麼處理這個過程的呢??答案就是整型提公升。對比int型別小的型別的每一次表示式計算都伴隨整型提公升,所以在對char型的變數進行比較運算時(a > b,a < b,a==b這些比較運算),編譯器首先會對char型變數進行integer promotion,也就是將char型變數提公升成int型別的,然後再進行比較。

至於提公升的方法,是根據原始型別進行位擴充套件(如果原始型別為unsigned char,進行零擴充套件,如果原始型別為signed char,進行符號位擴充套件)到32位。拿上文**作為例子,a是signed char型的,a=-1在記憶體中的位儲存形式是0xff,把a賦值給b,隨意b在記憶體中的位儲存形式也是0xff;然後就是a與b進行比較運算了,編譯器會把a,b都提公升到int型別,那麼原來a在記憶體中的位形式是0xff,提公升為int型別後會變成0xffffffff(符號位擴充套件),原來b在記憶體中的位形式是0xff,提示為int型別後會變成0x000000ff(零擴充套件),可以看出,此時a是小於b的。等等?a < b?對的,沒錯,a是小於b的,因為integer promotion之後,a,b都暫時(只是暫時,僅僅只是在執行運算時提公升了)提公升為int型別了,也就是signed int型別。

其實char a += 1;這個表示式就已經隱含了integer promotion。

為什麼編譯器要進行integer promotion?

學過微機原理或者學習過彙編的同學可能會知道,在我們的cpu中有乙個算術邏輯單元(arithmetic&logical unit),簡稱alu,主要功能是進行二位元的算術運算,如加減乘(不包括整數除法)和暫存器中的值之間的邏輯運算。那麼,我們的c/c++程式進行的運算最終也是要在alu中進行的,以32位cpu為例,暫存器都是32位的(剛好是乙個int型別所占用的位數),想要把char型別的變數送進alu中運算,那必然是需要把char型別變成32位,然後通過32位暫存器送入alu,那麼這個時候integer promotion的意義就出來了,如果不這樣進行提公升,alu就無法對char型別的變數進行運算了。

上面說了整型提公升,只是針對表示式中沒有比int型別大的資料型別。其實在進行運算時,是以表示式中最長型別為準的,將其他型別轉換成該型別,具體的規則如下:

比int型別小的型別(char, signed char, unsigned char, short, unsigned short),先經過整型提公升,提公升為int型別,然後int型別再根據表示式中最長型別轉換為該型別。

int、long(4位元組) –>> unsinged int、unsinged long(4位元組) –>> long long (8位元組)–>> unsigned long long (8位元組)<<– double(8位元組) <<– float(4位元組) (32位系統中)

float –>> int(32位系統中)

double –>> long long

下面還是來看看一段程式,與第一段程式做個對比

#include 

int main()

執行結果如下:

a==b

對比下第一段程式,我們很快就能發現區別!

前面提到的都是在進行計算時存在的隱式型別轉換,還要特別說明的就是在進行賦值操作時,賦值運算子右邊的資料型別必須轉換成賦值號左邊的型別,若右邊的資料型別的長度大於左邊,則要進行截斷或捨入操作

下面用一例項說明:

char ch;

int i,result;

float f;

double d;

result=ch/i+(f*d-i);

(1)首先計算 ch/i,ch → int型,ch/i → int型。

(2)接著計算 f*d-i,由於最長型為double型,故f→double型,i→double型,f*d-i→double型。

(3)(ch/i) 和(f*d-i)進行加運算,由於f*d-i為double型,故ch/i→double型,ch/i+(f*d-i)→double型。

(4)由於result為int型,故ch/i+(f*d-i)→double→int,即進行截斷與捨入,最後取值為整型。

C 隱式型別轉換

c 定義了一組內建型別物件之間的轉換標準,在必要時它們被編譯器隱式的應用到物件上。發生隱式型別轉換的情景 1,在混合型別的算術表示式中 轉換原則 轉換為最寬的資料型別。也可叫,算術轉換。int ival 5 double dval 3.14 ival 被提公升為double型別 ival dval ...

C 隱式型別轉換

眾所周知,c 的基本型別中並非完全的對立,部分資料型別之間是可以進行隱式轉換的。所謂隱式轉換,是指不需要使用者干預,編譯器私下進行的型別轉換行為。很多時候使用者可能都不知道進行了哪些轉換。c 物件導向的多型特性,就是通過父類的型別實現對子類的封裝。通過隱式轉換,你可以直接將乙個子類的物件使用父類的型...

C 隱式型別轉換

c primer 中提到 可以用 單個形參來呼叫 的建構函式定義了從 形參型別 到 該類型別 的乙個隱式轉換。這裡應該注意的是,可以用單個形參進行呼叫 並不是指建構函式只能有乙個形參,而是它可以有多個形參,但那些形參都是有預設實參的。那麼,什麼是 隱式轉換 呢?上面這句話也說了,是從 建構函式形參型...