?
一、自動類型轉(zhuǎn)換
??? 一般來說,同一句語句或表達式應(yīng)該使用同一種類型的變量和常量。如果使用了多種類型的變量和常量(類型混用),C 會自動把它們轉(zhuǎn)換成同一種類型。自動類型轉(zhuǎn)換為我們寫程序提供了方便,卻也帶來了危機。因粗心大意而造成的類型混用也許會導(dǎo)致程序運行出錯。以下是自動類型轉(zhuǎn)換的基本規(guī)則:
??? 1. 在表達式中,char 和 short 類型的值,無論有符號還是無符號,都會自動轉(zhuǎn)換成 int 或者 unsigned int(如果 short 的大小和 int 一樣,unsigned short 可表示的最大值就大于 int,在這種情況下,unsigned short 被轉(zhuǎn)換成 unsigned int)。因為它們被轉(zhuǎn)換成表示范圍更大的類型,故而我們把這種轉(zhuǎn)換稱之為“升級(promotion)”。
??? 2. 按照從高到低的順序給各種數(shù)據(jù)類型分等級,依次為:long double, double, float, unsigned long long, long long, unsigned long, long, unsigned int 和 int。這里有一個小小的例外,如果 long 和 int 大小相同,則 unsigned int 的等級應(yīng)位于 long 之上。char 和 short 并沒有出現(xiàn)于這個等級列表,是因為它們參與運算時就應(yīng)該已經(jīng)被升級成了 int 或者 unsigned int。
??? 3. 在任何涉及兩種數(shù)據(jù)類型的操作中,它們之間等級較低的類型會被轉(zhuǎn)換成等級較高的類型。
??? 4. 在賦值語句中,= 右邊的值在賦予 = 左邊的變量之前,首先要將右邊的值的數(shù)據(jù)類型轉(zhuǎn)換成左邊變量的類型。也就是說,左邊變量是什么數(shù)據(jù)類型,右邊的值就要轉(zhuǎn)換成什么數(shù)據(jù)類型的值。這個過程可能導(dǎo)致右邊的值的類型升級,也可能導(dǎo)致其類型降級(demotion)。所謂“降級”,是指等級較高的類型被轉(zhuǎn)換成等級較低的類型。
??? 5. 作為參數(shù)傳遞給函數(shù)時,char 和 short 會被轉(zhuǎn)換成 int,float 會被轉(zhuǎn)換成 double。使用函數(shù)原型可以避免這種自動升級。這點我以后會詳細講解。
??? 類型升級通常不會有什么問題,但是類型降級卻會帶來不少問題。例如:
??????? char ch = 1222;
1222 降級為 char,但 char 無法表示 1222。再如:
??????? int j = 22.2;
22.2 降級為 int,小數(shù)部分被截斷。
二、類型轉(zhuǎn)換運算符
??? 使用類型轉(zhuǎn)換運算符可以指定我們想要進行的類型轉(zhuǎn)換。類型轉(zhuǎn)換運算符由括號和類型名組成:
??????? (type)
其中,我們應(yīng)該用我們想轉(zhuǎn)換成的類型替換掉 type,例如:(long), (unsigned long)。
??? 類型轉(zhuǎn)換運算符應(yīng)該放在值的前面:
??????? int i = (int)1.1 + (int)2.2;
1.1 在加法運算前就因為類型轉(zhuǎn)換運算符而降級為 int,其值變?yōu)?1。類似地,2.2 也降級為 int,其值變?yōu)?2。又如:
??????? int j = 20;
??????? double k = (double)j;
j 的值被轉(zhuǎn)換成 double,然后用于初始化 k。
三、小例子
??? #include <stdio.h>
??? int main(void)
??? {
??????? char ch;
??????? int i;
??????? float fl;
??????? double db;
??????? db = fl = i = ch = 'C';???????????????? /* 10 */
??????? printf("ch=%c, i=%d, fl=%2.2f, db=%2.2f\n", ch, i, fl, db);
??????? ch = ch + 1;??????????????????????????? /* 13 */
??????? i = db + fl + 2 * ch;?????????????????? /* 14 */
??????? fl = 2.0 * ch + i;????????????????????? /* 15 */
??????? db = 22 * i + ch - fl;????????????????? /* 16 */
??????? printf("ch=%c, i=%d, fl=%2.2f, db=%2.2f\n", ch, i, fl, db);
??????? i = 666.6 + 777.7;????????????????????? /* 19 */
??????? printf("Now i = %d\n", i);
??????? i = (int)666.6 + (int)777.7;??????????? /* 21 */
??????? printf("Now i = %d\n", i);
??????? return 0;
??? }
我的系統(tǒng)中,char 是 8 位的,int 是 32 位的。輸出為:
??? ch=C, i=67, fl=67.00, db=67.00
??? ch=D, i=270, fl=406.00, db=5602.00
??? Now i = 1444
??? Now i = 1443
第 10 行,'C' 的值被轉(zhuǎn)換為 char,然后賦值給 ch。ch 的值被轉(zhuǎn)換成 int,然后賦值給 i。以此類推。
第 13 行,= 右邊的 ch 的值先被轉(zhuǎn)換成 int,然后和 1 相加,得到 32 位的 int 類型整數(shù) 68。最后,68 降級為 char,然后賦值給 ch。在 ASCII 中,D 的編碼是 68。
第 14 行,ch 的值被轉(zhuǎn)換成 int,然后和 2 相乘得 136。fl 的值被轉(zhuǎn)換成 double,然后和 db 相加,其和再與轉(zhuǎn)換成 double 的 136 相加得 270.0 。最后,270.0 被轉(zhuǎn)換成 int,然后賦值給 i。
第 15 行,ch 的值被轉(zhuǎn)換成 double,然后和 2.0 相乘,i 的值被轉(zhuǎn)換成 double,然后和前面得到的乘積相加,相加的得數(shù)被轉(zhuǎn)換成 float,然后賦值給 fl。
第 16 行,22 和 i 相乘得 5940,ch 的值被轉(zhuǎn)換成 int,然后和 5940 相加得 6008,然后,6008 被轉(zhuǎn)換成 float,再和 fl 相減得 5602.0f,最后 5602.0f 被轉(zhuǎn)換成 double,再賦值給 db。
第 19 行,666.6 和 777.7 相加得 1444.3,然后 1444.3 被降級成 int,再賦值給 i。
第 21 行,類型轉(zhuǎn)換運算符把 666.6 和 777.7 轉(zhuǎn)換為 int,得 666 和 777,它們相加得 1443,最后,1443 被賦值給 i。
注意,類型轉(zhuǎn)換改變的是值的類型,而不是對象的類型,對象的類型自始至終都是不變的。例如:
??? i = fl + ch;
ch 的值被轉(zhuǎn)換成 float,而 ch 本身仍然是 char 類型的變量。
參考資料:C Primer 5th Edition
??????????The C Programming Language 2nd Edition
????????? C99 標(biāo)準(zhǔn)