天天看點

類型轉換

Integer Promotion

在一個表達式中,凡是可以使用int或unsigned int類型做右值的地方也都可以使用有符号或無符号的char型、 short型和Bit-field。如果原始類型的取值範圍都能用int型表示,則其值被提升為int型,如果表示不了就提升為unsigned int型,這稱為Integer Promotion。做IntegerPromotion隻影響上述幾種類型的值,對其它類型無影響。

Integer Promotion适用于以下幾種情況:

(1)如果一個函數的形參類型未知,或者函數的參數清單中有...,那麼調用函數時要對相應的實參做Integer Promotion,此外,相應的實參如果是float型的也要被提升為double型,這條規則稱為Default Argument Promotion。

例如:printf的參數清單中有...,除了第一個形參之外,其它形參的類型都是未知的,是以我們在調用printf("%c", 'A')時,'A'其實被提升為int型之後才傳給了printf。

(2)算術運算中的類型轉換。兩個算術類型的操作數做算術運算,比如a * b,如果兩邊操作數的類型不同,編譯器會自動做類型轉換,使兩邊類型相同之後才做運算,這稱為Usual Arithmetic Conversion,轉換過程中有一步就是Integer Promotion。

例如:

unsigned char c1 = 255, c2 = 2;
int n = c1 + c2;      

計算表達式c1 + c2的過程其實是先把c1和c2提升為int類型然後相加( unsigned char的取值範圍是0~255,完全可以用int表示,是以不需要提升為unsigned int),整個表達式的值也是int型,最後的結果是257。假如沒有這個提升的過程, c1 + c2就溢出了。 

Usual Arithmetic Conversion

1. 如果有一邊的類型是long double,則把另一邊也轉成long double。

2. 否則,如果有一邊的類型是double,則把另一邊也轉成double。

3. 否則,如果有一邊的類型是float,則把另一邊也轉成float。

4. 否則,兩邊應該都是整數類型,做Integer Promotion,然後如果類型仍不相同,則需要繼續轉換。首先規定char、 short、 int、 long、 long long的轉換級别( Integer Conversion Rank) 一個比一個高,同一類型的有符号和無符号數具有相同的Rank,然後有如下轉換規則:

a. 如果兩邊都是有符号數,或者都是無符号數,那麼較低Rank的類型轉換成較高Rank的類型。例如unsigned int和unsigned long做算術運算時都轉成unsigned long。

b. 否則,如果一邊是無符号數另一邊是有符号數,無符号數的Rank不低于有符号數的Rank,則把有符号數轉成另一邊的無符号類型。例如unsigned long和int做算術運算時都轉成unsigned long, unsigned long和long做算術運算時也都轉成unsignedlong。

c. 剩下的情況就是:一邊是無符号數另一邊是有符号數,并且無符号數的Rank低于有符号數的Rank。這時又分為兩種情況,如果這個有符号數類型能夠覆寫這個無符号數類型的取值範圍,則把無符号數轉成另一邊的有符号類型。例如遵循LP64的平台上unsigned int和long在做算術運算時都轉成long。

d. 否則,也就是這個符号數類型不足以覆寫這個無符号數類型的取值範圍,則把兩邊都轉成兩者之中較高Rank的無符号類型。例如遵循ILP32的平台上unsigned int和long在做算術運算時都轉成unsigned long。 

由指派産生的類型轉換 

如果指派或初始化時等号兩邊的類型不相同,則編譯器會把等号右邊的類型轉換成等号左邊的類型再做指派。例如int c = 3.14;,編譯器會把右邊的double型轉成int型再賦給變量c。 

函數調用傳參的過程相當于定義形參并且用實參對其做初始化,函數傳回的過程相當于定義一個臨時變量并且用return的表達式對其做初始化,是以由指派産生的類型轉換也适用于這兩種情況。例如一個函數的原型是int foo(int, int);,則調用foo(3.1, 4.2)時會自動把兩個double型的實參轉成int型賦給形參,如果這個函數定義中有傳回語句return 1.2;,則傳回值1.2會自動轉成int型再傳回。 

強制類型轉換

上一篇: 類型轉換
下一篇: 類型轉換