1. C語言中的數據類型
C語言中的類型按其組成可以分為簡單類型和構造類型,按是否預定義了類型名字和值集可以分為基本類型和非基本類型,按是否加了類型限定符可以分為限定類型和非限定類型。
ANSI C99標准中類型定義的BNF語法如下圖。

說明:
- typedef可以定義新數據類型,如typedef long int FOUR_BYTE_INT,即定義了和long int一樣的數據類型FOUR_BYTE_INT。
- 如果typedef時加入了類型限定符或存儲區分符,比如typedef volatile char KEYBOARD,則KEYBOARD k等價於volatile char。
- 按照一般規范,新定義的數據類型同義名需要全部大寫,以免與變量名混淆。
- 利用類型定義typedef,可以為所要表示對象指定比原數據類型更合適的名字,如typedef float SPEED。
- 利用類型定義typedef,可以提高的程序的在不同編譯器上升級的可維護性,比如有些類型在某些編譯器下沒有,只需要改變類型定義即可輕松維護。
- 類型定義typedef一般用於定義比較長或復雜的名字,如struct類型,即便於書寫,又提高了程序的可讀性。
- 類型定義typedef與預處理指令#define的區別:
- 處理時間不同:前者是編譯過程中,后者是編譯過程前;
- 處理方法不同:前者是類型替換,而后者是簡單的字符串替換,在某些情況下不適合,比如定義多個變量的地方:
1 #define POINTER int *;
2 POINTER a,b;
-
-
- 如果是想定義兩個指針類型a,b,預處理后是int * a,b。只有a是int *,是錯誤的。
-
ANSI C99標准中規定的數據類型如下圖所示。

說明:
- 同一行類型的語義相同,即可以相互替代。
- long float類型與double相同,故在C99標准中沒有此類型。
- 部分編譯器也提供了unsigned float和unsigned double,最好不要使用,以免影響程序的可移植性。
- int默認是signed,所以int, signed, signed int三者等價。其它unsigned的情況類似。char默認情況不確定。
2. C語言中數據類型的長度
ANSI C99標准中定義了兩類(四個)類型修飾符:long/short和unsigned/signed。
C99標准規定,long類型不能比變通類型短,short類型不能比普通類型長。而unsigned與signed的區別在實現上是有無符號的區別,而是使用上是取值范圍的區別,兩者表示范圍相同,但前者全是正數,后者關於0對稱。
說明:
- long/short可以修飾int,long還可以修飾double。
- unsigned/signed可以修飾int, char,不可以修飾浮點型。
- int長度是機器的字長,short int是半個字長,long int是一個或兩個字長。
- unsigned/signed長度與普通類型一樣,只是表示區間不同。
3. C語言中數據類型的轉換
類型轉換分為顯示和隱式兩種,前者比較簡單,這里只講后者。下面是C99標准中給出的各種類型對象的基本轉換規則:
- 枚舉常量:轉換成int,如超出int范圍,則轉成long int等
- 浮點類型:
- 如果轉成整類型,只保留整數部分,如果超出整類型表示范圍,則轉換錯誤;
- 如果向上轉成double/long double,值不變;
- 如果向下轉成float/double等,如果能用float/double表示,則正常,如果超出表示范圍,則轉換錯誤,而如果在表示范圍內,但精度降低,則要依賴於編譯器的處理了;
- 整類型:short int/char/枚舉類型/位域類型都可轉換成int,如果超出int表示范圍,則提升到unsigned int。
- 對於二元運算符中的普通算術運算轉換,C99標准給出了如下圖所示的轉換規則:

說明:
- 對於unsigned char和unsigned short int的整型提升問題,C99標准給出“保值”的轉換方法:方法是將unsigned char和unsigned short int轉換成int,如果超出表示范圍,則轉成unsigned int。
- 對於表格中第五行,long int與unsigned int的情況,在vc6.0沒有這樣實現,是直接轉成unsigned int。
4. 測試練習
1 char a = 0xb6;
2 short b = 0xb600;
3 int c = 0xb6000000;
4
5 if ( a == 0xb6) puts("a");
6 if ( b == 0xb600) puts("b");
7 if ( c == 0xb6000000) puts("c");
答案:
在VC或x86的gcc下,只會打印出 c ,而linux的gcc則會打印出a和c。
解釋:
char在前兩者默認是signed char,而后者默認是unsigned char。因此當整型提升時,在前兩者的編譯器下,三條語句分別變成如下情況:
1 if ( 0xffffffb6 == 0x000000b6) puts("a");
2 if ( 0xffffb600 == 0x0000b600) puts("b");
3 if ( 0xb6000000 == 0xb6000000) puts("c");
而在linux的gcc編譯下,則是下面的情況:
1 if ( 0x000000b6 == 0x000000b6) puts("a");
2 if ( 0xffffb600 == 0x0000b600) puts("b");
3 if ( 0xb6000000 == 0xb6000000) puts("c");