1. 程式人生 > 其它 >C 語言中的基本資料型別

C 語言中的基本資料型別

目錄

本文將詳細介紹 C 語言的基本資料型別,包括如何宣告變數、如何表示字面值常量(如,5 或 2.78),以及典型的用法。一些老式的 C 語言編譯器無法支援這裡提到的所有型別,請查閱你使用的編譯器文件,瞭解可以使用哪些型別。

一、int 型別

C 語言提供了許多整數型別,為什麼一種型別不夠用?因為 C 語言讓程式設計師針對不同情況選擇不同的型別。特別是,C 語言中的整數型別可表示不同的取值範圍和正負值。一般情況使用 int 型別即可,但是為滿足特定任務和機器的要求,還可以選擇其他型別。

int 型別是有符號整型,即 int 型別的值必須是整數,可以是正整數、負整數或零。其取值範圍依計算機系統而異。一般而言,儲存一個 int 要佔用一個機器字長。因此,早期的 16 位 IBM PC 相容機使用 16 位來儲存一個 int 值,其取值範圍(即 int 值的取值範圍)是 -32768~32767。目前的個人計算機一般是 32 位,因此用 32 位儲存一個 int 值。現在,個人計算機產業正逐步向著 64 位處理器發展,自然能儲存更大的整數。ISO C 規定 int 的取值範圍最小為 -32768~32767。一般而言,系統用一個特殊位的值表示有符號整數的正負號。

1.1 宣告 int 變數

先寫上 int,然後寫變數名,最後加上一個分號。要宣告多個變數,可以單獨宣告每個變數,也可在 int 後面列出多個變數名,變數名之間用逗號分隔。下面都是有效的宣告:

int erns;
int hogs, cows, goats;

可以分別在 4 條宣告中宣告各變數,也可以在一條宣告中宣告 4 個變數。兩種方法的效果相同,都為 4 個 int 大小的變數賦予名稱並分配記憶體空間。

以上宣告建立了變數,但是並沒有給它們提供值。變數如何獲得值?前面介紹過在程式中獲取值的兩種途徑。第 1 種途徑是賦值:

cows = 112;

第 2 種途徑是,通過函式(如,scanf())獲得值。接下來,我們著重介紹第 3 種途徑。

1.2 初始化變數

初始化(initialize)變數就是為變數賦一個初始值。在 C 語言中,初始化可以直接在宣告中完成。只需在變數名後面加上賦值運算子(=)和待賦給變數的值即可。如下所示:

int hogs = 21;
int cows = 32, goats = 14;
int dogs, cats = 94; /* 有效,但是這種格式很糟糕 */

以上示例的最後一行,只初始化了 cats,並未初始化 dogs。這種寫法很容易讓人誤認為 dogs 也被初始化為 94,所以最好不要把初始化的變數和未初始化的變數放在同一條宣告中。

簡而言之,宣告為變數建立和標記儲存空間,併為其指定初始值(如圖 4 所示)。

圖 4 定義並初始化變數

1.3 int 型別常量

上面示例中出現的整數(21、32、14 和 94)都是整型常量或整型字面量。C 語言把不含小數點和指數的數作為整數。因此,22 和 -44 都是整型常量,但是 22.0 和 2.2E1 則不是。C 語言把大多數整型常量視為 int 型別,但是非常大的整數除外。詳見後面“long 常量和 long long 常量”小節對 long int 型別的討論。

1.4 列印 int 值

可以使用 printf() 函式列印 int 型別的值。%d 指明瞭在一行中列印整數的位置。%d 稱為轉換說明,它指定了 printf() 應使用什麼格式來顯示一個值。格式化字串中的每個 %d 都與待列印變數列表中相應的 int 值匹配。這個值可以是 int 型別的變數、int 型別的常量或其他任何值為 int 型別的表示式。作為程式設計師,要確保轉換說明的數量與待列印值的數量相同,編譯器不會捕獲這型別的錯誤。程式清單 2 演示了一個簡單的程式,程式中初始化了一個變數,並列印該變數的值、一個常量值和一個簡單表示式的值。另外,程式還演示瞭如果粗心犯錯會導致什麼結果。

程式清單 2 print1.c 程式

/* print1.c - 演示printf()的一些特性 */
#include <stdio.h>
int main(void)
{
     int ten = 10;
     int two = 2;

     printf("Doing it right: ");
     printf("%d minus %d is %d\n", ten, 2, ten - two);
     printf("Doing it wrong: ");
     printf("%d minus %d is %d\n", ten);  // 遺漏2個引數

     return 0;
}

編譯並執行該程式,輸出如下:

Doing it right: 10 minus 2 is 8
Doing it wrong: 10 minus 16 is 1650287143

在第一行輸出中,第 1 個 %d 對應 int 型別變數 ten;第 2 個 %d 對應 int 型別常量 2;第 3 個 %d 對應 int 型別表示式 ten - two 的值。在第二行輸出中,第 1 個 %d 對應 ten 的值,但是由於沒有給後兩個 %d 提供任何值,所以打印出的值是記憶體中的任意值(讀者在執行該程式時顯示的這兩個數值會與輸出示例中的數值不同,因為記憶體中儲存的資料不同,而且編譯器管理記憶體的位置也不同)。

你可能會抱怨編譯器為何不能捕獲這種明顯的錯誤,但實際上問題出在 printf() 不尋常的設計。大部分函式都需要指定數目的引數,編譯器會檢查引數的數目是否正確。但是,printf() 函式的引數數目不定,可以有 1 個、2 個、3 個或更多,編譯器也愛莫能助。記住,使用 printf() 函式時,要確保轉換說明的數量與待列印值的數量相等。

1.5 八進位制和十六進位制

通常,C 語言都假定整型常量是十進位制數。然而,許多程式設計師很喜歡使用八進位制和十六進位制數。因為 8 和 16 都是 2 的冪,而 10 卻不是。顯然,八進位制和十六進位制記數系統在表達與計算機相關的值時很方便。例如,十進位制數 65536 經常出現在 16 位機中,用十六進位制表示正好是 10000。另外,十六進位制數的每一位的數恰好由 4 位二進位制數表示。例如,十六進位制數 3 的二進位制數是 0011,十六進位制數 5 的二進位制數是 0101。因此,十六進位制數35的位組合(bit pattern)是 00110101,十六進位制數 53 的位組合是 01010011。這種對應關係使得十六進位制和二進位制的轉換非常方便。但是,計算機如何知道 10000 是十進位制、十六進位制還是二進位制?在 C 語言中,用特定的字首表示使用哪種進位制。0x 或 0X 字首表示十六進位制值,所以十進位制數 16 表示成十六進位制是 0x10 或 0X10。與此類似,0 字首表示八進位制。例如,十進位制數 16 表示成八進位制是 020。

要清楚,使用不同的進位制數是為了方便,不會影響數被儲存的方式。也就是說,無論把數字寫成 16、020 或 0x10,儲存該數的方式都相同,因為計算機內部都以二進位制進行編碼。

1.6 顯示八進位制和十六進位制

在 C 程式中,既可以使用也可以顯示不同進位制的數。不同的進位制要使用不同的轉換說明。以十進位制顯示數字,使用 %d;以八進位制顯示數字,使用 %o;以十六進位制顯示數字,使用 %x。另外,要顯示各進位制數的字首 0、0x 和 0X,必須分別使用 %#o%#x%#X。程式清單 3 演示了一個小程式(回憶一下,在某些整合開發環境(IDE)下編寫的程式碼中插入 getchar(); 語句,程式在執行完畢後不會立即關閉執行視窗)。

程式清單 3 bases.c 程式

/* bases.c--以十進位制、八進位制、十六進位制列印十進位制數100 */
#include <stdio.h>
int main(void)
{
     int x = 100;

     printf("dec = %d; octal = %o; hex = %x\n", x, x, x);
     printf("dec = %d; octal = %#o; hex = %#x\n", x, x, x);

     return 0;
}

編譯並執行該程式,輸出如下:

dec = 100; octal = 144; hex = 64
dec = 100; octal = 0144; hex = 0x64

該程式以 3 種不同記數系統顯示同一個值。printf() 函式做了相應的轉換。注意,如果要在八進位制和十六進位制值前顯示 0 和 0x 字首,要分別在轉換說明中加入 #。

二、其他整數型別

初學 C 語言時,int 型別應該能滿足大多數程式的整數型別需求。儘管如此,還應瞭解一下整型的其他形式。

C 語言提供 3 個附屬關鍵字修飾基本整數型別:short、long 和 unsigned。應記住以下幾點。

  • short int 型別(或者簡寫為 short)佔用的儲存空間可能比 int 型別少,常用於較小數值的場合以節省空間。與 int 類似,short 是有符號型別。
  • long int 或 long 佔用的儲存空間可能比 int 多,適用於較大數值的場合。與 int 類似,long 是有符號型別。
  • long long int 或 long long(C99 標準加入)佔用的儲存空間可能比 long 多,適用於更大數值的場合。該型別至少佔 64 位。與 int 類似,long long 是有符號型別。
  • unsigned int 或 unsigned 只用於非負值的場合。這種型別與有符號型別表示的範圍不同。例如,16 位 unsigned int 允許的取值範圍是 0~65535,而不是 -32768~32767。用於表示正負號的位現在用於表示另一個二進位制位,所以無符號整型可以表示更大的數。
  • 在 C90 標準中,添加了 unsigned long int 或 unsigned long 和 unsigned short int 或 unsigned short 型別。C99 標準又添加了 unsigned long long int 或 unsigned long long。
  • 在任何有符號型別前面新增關鍵字 signed,可強調使用有符號型別的意圖。例如,short、short int、signed short、signed short int 都表示同一種類型。

2.1 宣告其他整數型別

其他整數型別的宣告方式與 int 型別相同,下面列出了一些例子。不是所有的 C 編譯器都能識別最後 3 條宣告,最後一個例子所有的型別是 C99 標準新增的。

long int estine;
long johns;
short int erns;
short ribs;
unsigned int s_count;
unsigned players;
unsigned long headcount;
unsigned short yesvotes;
long long ago;

2.2 使用多種整數型別的原因

為什麼說 short 型別“可能”比 int 型別佔用的空間少,long 型別“可能”比 int 型別佔用的空間多?因為 C 語言只規定了 short 佔用的儲存空間不能多於 int,long 佔用的儲存空間不能少於 int。這樣規定是為了適應不同的機器。例如,過去的一臺執行 Windows 3.x 的機器上,int 型別和 short 型別都佔 16 位,long 型別佔 32 位。後來,Windows 和蘋果系統都使用 16 位儲存 short 型別,32 位儲存 int 型別和 long 型別(使用 32 位可以表示的整數數值超過 20 億)。現在,計算機普遍使用 64 位處理器,為了儲存 64 位的整數,才引入了 long long 型別。

現在,個人計算機上最常見的設定是,long long 佔 64 位,long 佔 32 位,short 佔 16 位,int 佔 16 位或 32 位(依計算機的自然字長而定)。原則上,這 4 種類型代表 4 種不同的大小,但是在實際使用中,有些型別之間通常有重疊。

C 標準對基本資料型別只規定了允許的最小大小。對於 16 位機,short 和 int 的最小取值範圍是 [−32768,32767];對於 32 位機,long 的最小取值範圍是 [−2147483648,2147483647]。對於 unsigned short 和 unsigned int,最小取值範圍是 [0,65535];對於 unsigned long,最小取值範圍是 [0,4294967295]。long long 型別是為了支援 64 位的需求,最小取值範圍是 [−9223372036854775808,9223372036854775807];unsigned long long 的最小取值範圍是 [0,18446744073709551615]。如果要開支票,這個數是一千八百億億六千七百四十四萬億零七百三十七億零九百五十五萬一千六百一十五。但是,誰會去數?

int 型別那麼多,應該如何選擇?首先,考慮 unsigned 型別。這種型別的數常用於計數,因為計數不用負數。而且,unsigned 型別可以表示更大的正數。

如果一個數超出了 int 型別的取值範圍,且在 long 型別的取值範圍內時,使用 long 型別。然而,對於那些 long 佔用的空間比 int 大的系統,使用 long 型別會減慢運算速度。因此,如非必要,請不要使用 long 型別。另外要注意一點:如果在 long 型別和 int 型別佔用空間相同的機器上編寫程式碼,當確實需要 32 位的整數時,應使用 long 型別而不是 int 型別,以便把程式移植到 16 位機後仍然可以正常工作。類似地,如果確實需要 64 位的整數,應使用 long long 型別。

如果在 int 設定為 32 位的系統中要使用 16 位的值,應使用 short 型別以節省儲存空間。通常,只有當程式使用相對於系統可用記憶體較大的整型陣列時,才需要重點考慮節省空間的問題。使用 short 型別的另一個原因是,計算機中某些元件使用的硬體暫存器 是16 位。

2.3 long 常量和 long long 常量

通常,程式程式碼中使用的數字(如,2345)都被儲存為 int 型別。如果使用 1000000 這樣的大數字,超出了 int 型別能表示的範圍,編譯器會將其視為 long int 型別(假設這種型別可以表示該數字)。如果數字超出 long 可表示的最大值,編譯器則將其視為 unsigned long 型別。如果還不夠大,編譯器則將其視為 long long 或 unsigned long long 型別(前提是編譯器能識別這些型別)。

八進位制和十六進位制常量被視為 int 型別。如果值太大,編譯器會嘗試使用 unsigned int。如果還不夠大,編譯器會依次使用 long、unsigned long、long long 和 unsigned long long 型別。

有些情況下,需要編譯器以 long 型別儲存一個小數字。例如,程式設計時要顯式使用 IBM PC 上的記憶體地址時。另外,一些 C 標準函式也要求使用 long 型別的值。要把一個較小的常量作為 long 型別對待,可以在值的末尾加上 l(小寫的 L)或 L 字尾。使用 L 字尾更好,因為 l 看上去和數字 1 很像。因此,在 int 為 16 位、long 為 32 位的系統中,會把 7 作為 16 位儲存,把 7L 作為 32 位儲存。l 或 L 字尾也可用於八進位制和十六進位制整數,如 020L 和 0x10L。

類似地,在支援 long long 型別的系統中,也可以使用 ll 或 LL 字尾來表示 long long 型別的值,如 3LL。另外,u 或 U 字尾表示 unsigned long long,如 5ull、10LLU、6LLU 或 9Ull。

整數溢位

如果整數超出了相應型別的取值範圍會怎樣?下面分別將有符號型別和無符號型別的整數設定為比最大值略大,看看會發生什麼(printf() 函式使用 %u 說明顯示 unsigned int 型別的值)。

/* toobig.c-- 超出系統允許的最大int值*/
#include <stdio.h>
int main(void)
{
    int i = 2147483647; 
     unsigned int j = 4294967295;

     printf("%d %d %d\n", i, i+1, i+2);
     printf("%u %u %u\n", j, j+1, j+2);

     return 0;
}

在我們的系統下輸出的結果是:

2147483647    -2147483648    -2147483647
4294967295    0    1

可以把無符號整數 j 看作是汽車的里程錶。當達到它能表示的最大值時,會重新從起始點開始。整數 i 也是類似的情況。它們主要的區別是,在超過最大值時,unsigned int 型別的變數 j 從 0 開始;而 int 型別的變數 i 則從 −2147483648 開始。注意,當 i 超出(溢位)其相應型別所能表示的最大值時,系統並未通知使用者。因此,在程式設計時必須自己注意這類問題。

溢位行為是未定義的行為,C 標準並未定義有符號型別的溢位規則。以上描述的溢位行為比較有代表性,但是也可能會出現其他情況。

2.4 列印 short、long、long long 和 unsigned 型別

列印 unsigned int 型別的值,使用 %u 轉換說明;列印 long 型別的值,使用 %ld 轉換說明。如果系統中 int 和 long 的大小相同,使用 %d 就行。但是,這樣的程式被移植到其他系統(int 和 long 型別的大小不同)中會無法正常工作。在 x 和 o 前面可以使用 l 字首,%lx 表示以十六進位制格式列印 long 型別整數,%lo 表示以八進位制格式列印 long 型別整數。注意,雖然 C 允許使用大寫或小寫的常量字尾,但是在轉換說明中只能用小寫。

C 語言有多種 printf() 格式。對於 short 型別,可以使用h字首。%hd 表示以十進位制顯示 short 型別的整數,%ho 表示以八進位制顯示 short 型別的整數。h 和 l 字首都可以和 u 一起使用,用於表示無符號型別。例如,%lu表示列印 unsigned long 型別的值。程式清單 4 演示了一些例子。對於支援 long long 型別的系統,%lld%llu 分別表示有符號和無符號型別。

程式清單 4 print2.c 程式

/* print2.c--更多printf()的特性 */
#include <stdio.h>
int main(void)
{
     unsigned int un = 3000000000; /* int為32位和short為16位的系統 */
     short end = 200;
     long big = 65537;
     long long verybig = 12345678908642;

     printf("un = %u and not %d\n", un, un);
     printf("end = %hd and %d\n", end, end);
     printf("big = %ld and not %hd\n", big, big);
     printf("verybig= %lld and not %ld\n", verybig, verybig);

     return 0;
}

在特定的系統中輸出如下(輸出的結果可能不同):

un = 3000000000 and not -1294967296
end = 200 and 200
big = 65537 and not 1
verybig= 12345678908642 and not 1942899938

該例表明,使用錯誤的轉換說明會得到意想不到的結果。第 1 行輸出,對於無符號變數 un,使用 %d 會生成負值!其原因是,無符號值 3000000000 和有符號值 −129496296 在系統記憶體中的內部表示完全相同。因此,如果告訴 printf() 該數是無符號數,它列印一個值;如果告訴它該數是有符號數,它將列印另一個值。在待列印的值大於有符號值的最大值時,會發生這種情況。對於較小的正數(如 96),有符號和無符號型別的儲存、顯示都相同。

第 2 行輸出,對於 short 型別的變數 end,在 printf() 中無論指定以 short 型別(%hd)還是 int 型別(%d)列印,打印出來的值都相同。這是因為在給函式傳遞引數時,C 編譯器把 short 型別的值自動轉換成 int 型別的值。你可能會提出疑問:為什麼要進行轉換?h 修飾符有什麼用?第 1 個問題的答案是,int 型別被認為是計算機處理整數型別時最高效的型別。因此,在 short 和 int 型別的大小不同的計算機中,用 int 型別的引數傳遞速度更快。第 2 個問題的答案是,使用 h 修飾符可以顯示較大整數被截斷成 short 型別值的情況。第 3 行輸出就演示了這種情況。把 65537 以二進位制格式寫成一個 32 位數是 00000000000000010000000000000001。使用 %hd,printf() 只會檢視後 16 位,所以顯示的值是 1。與此類似,輸出的最後一行先顯示了 verybig 的完整值,然後由於使用了 %ld,printf() 只顯示了儲存在後 32 位的值。

前面介紹過,程式設計師必須確保轉換說明的數量和待列印值的數量相同。以上內容也提醒讀者,程式設計師還必須根據待列印值的型別使用正確的轉換說明。

提示 匹配 printf() 說明符的型別

在使用printf()函式時,切記檢查每個待列印值都有對應的轉換說明,還要檢查轉換說明的型別是否與待列印值的型別相匹配。

三、使用字元:char 型別

char 型別用於儲存字元(如,字母或標點符號),但是從技術層面看,char 是整數型別。因為 char 型別實際上儲存的是整數而不是字元。計算機使用數字編碼來處理字元,即用特定的整數表示特定的字元。美國最常用的編碼是 ASCII 編碼。例如,在 ASCII 碼中,整數 65 代表大寫字母 A。因此,儲存字母 A 實際上儲存的是整數 65(許多 IBM 的大型主機使用另一種編碼——EBCDIC,其原理相同。另外,其他國家的計算機系統可能使用完全不同的編碼)。

標準 ASCII 碼的範圍是 0~127,只需 7 位二進位制數即可表示。通常,char 型別被定義為 8 位的儲存單元,因此容納標準 ASCII 碼綽綽有餘。許多其他系統(如 IMB PC 和蘋果 Macs)還提供擴充套件 ASCII 碼,也在 8 位的表示範圍之內。一般而言,C 語言會保證 char 型別足夠大,以儲存系統(實現 C 語言的系統)的基本字符集。

許多字符集都超過了 127,甚至多於 255。例如,日本漢字(kanji)字符集。商用的統一碼(Unicode)建立了一個能表示世界範圍內多種字符集的系統,目前包含的字元已超過 110000 個。國際標準化組織(ISO)和國際電工技術委員會(IEC)為字符集開發了 ISO/IEC 10646 標準。統一碼標準也與 ISO/IEC 10646 標準相容。

C 語言把 1 位元組定義為 char 型別佔用的位(bit)數,因此無論是 16 位還是 32 位系統,都可以使用 char 型別。

3.1 宣告 char 型別變數

char 型別變數的宣告方式與其他型別變數的宣告方式相同。下面是一些例子:

char response;
char itable, latan;

以上宣告建立了 3 個 char 型別的變數:response、itable 和 latan。

3.2 字元常量和初始化

如果要把一個字元常量初始化為字母 A,不必背下 ASCII 碼,用計算機語言很容易做到。通過以下初始化把字母 A 賦給 grade 即可:

char grade = 'A';

在 C 語言中,用單引號括起來的單個字元被稱為字元常量(character constant)。編譯器一發現 'A',就會將其轉換成相應的程式碼值。單引號必不可少。下面還有一些其他的例子:

char broiled;       /* 宣告一個char型別的變數 */
broiled = 'T';      /* 為其賦值,正確 */
broiled = T;        /* 錯誤!此時T是一個變數 */
broiled = "T";      /* 錯誤!此時"T"是一個字串 */

如上所示,如果省略單引號,編譯器認為 T 是一個變數名;如果把 T 用雙引號括起來,編譯器則認為 "T" 是一個字串。

實際上,字元是以數值形式儲存的,所以也可使用數字程式碼值來賦值:

char grade = 65; /* 對於ASCII,這樣做沒問題,但這是一種不好的程式設計風格 */

在本例中,雖然 65 是 int 型別,但是它在 char 型別能表示的範圍內,所以將其賦值給 grade 沒問題。由於 65 是字母 A 對應的 ASCII 碼,因此本例是把 A 賦給 grade。注意,能這樣做的前提是系統使用 ASCII 碼。其實,用 'A' 代替 65 才是較為妥當的做法,這樣在任何系統中都不會出問題。因此,最好使用字元常量,而不是數字程式碼值。

奇怪的是,C 語言將字元常量視為 int 型別而非 char 型別。例如,在 int 為 32 位、char 為 8 位的 ASCII 系統中,有下面的程式碼:

char grade = 'B';

本來 'B' 對應的數值 66 儲存在 32 位的儲存單元中,現在卻可以儲存在 8 位的儲存單元中(grade)。利用字元常量的這種特性,可以定義一個字元常量 'FATE',即把 4 個獨立的 8 位 ASCII 碼儲存在一個 32 位儲存單元中。如果把這樣的字元常量賦給 char 型別變數 grade,只有最後 8 位有效。因此,grade 的值是 'E'

3.3 非列印字元

單引號只適用於字元、數字和標點符號,瀏覽 ASCII 表會發現,有些 ASCII 字元打印不出來。例如,一些代表行為的字元(如,退格、換行、終端響鈴或蜂鳴)。C 語言提供了 3 種方法表示這些字元。

第 1 種方法前面介紹過——使用 ASCII 碼。例如,蜂鳴字元的 ASCII 值是 7,因此可以這樣寫:

char beep = 7;

第 2 種方法是,使用特殊的符號序列表示一些特殊的字元。這些符號序列叫作轉義序列(escape sequence)。表 2 列出了轉義序列及其含義。

把轉義序列賦給字元變數時,必須用單引號把轉義序列括起來。例如,假設有下面一行程式碼:

char nerf = '\n';

稍後列印變數 nerf 的效果是,在印表機或螢幕上另起一行。

表 2 轉義序列

轉義序列 含義
\a 警報(ANSI C)
\b 退格
\f 換頁
\n 換行
\r 回車
\t 水平製表符
\v 垂直製表符
\\ 反斜槓(\)
\' 單引號
\" 雙引號
\? 問號
\0oo 八進位制值(oo必須是有效的八進位制數,即每個o可表示07中的一個數)
\xhh 十六進位制值(hh必須是有效的十六進位制數,即每個h可表示0f中的一個數)

現在,我們來仔細分析一下轉義序列。使用 C90 新增的警報字元(\a)是否能產生聽到或看到的警報,取決於計算機的硬體,蜂鳴是最常見的警報(在一些系統中,警報字元不起作用)。C 標準規定警報字元不得改變活躍位置。標準中的活躍位置(active position)指的是顯示裝置(螢幕、電傳打字機、印表機等)中下一個字元將出現的位置。簡而言之,平時常說的螢幕游標位置就是活躍位置。在程式中把警報字元輸出在螢幕上的效果是,發出一聲蜂鳴,但不會移動螢幕游標。

接下來的轉義字元 \b\f\n\r\t\v 是常用的輸出裝置控制字元。瞭解它們最好的方式是檢視它們對活躍位置的影響。換頁符(\f)把活躍位置移至下一頁的開始處;換行符(\n)把活躍位置移至下一行的開始處;回車符(\r)把活躍位置移動到當前行的開始處;水平製表符(\t)將活躍位置移至下一個水平製表點(通常是第 1 個、第 9 個、第 17 個、第 25 個等字元位置);垂直製表符(\v)把活躍位置移至下一個垂直製表點。

這些轉義序列字元不一定在所有的顯示裝置上都起作用。例如,換頁符和垂直製表符在 PC 螢幕上會生成奇怪的符號,游標並不會移動。只有將其輸出到印表機上時才會產生前面描述的效果。

接下來的 3 個轉義序列(\\\'\")用於列印 \'" 字元(由於這些字元用於定義字元常量,是 printf() 函式的一部分,若直接使用它們會造成混亂)。如果列印下面一行內容:

Gramps sez, "a \ is a backslash."

應這樣編寫程式碼:

printf("Gramps sez, \"a \\ is a backslash.\"\n");

表 2 中的最後兩個轉義序列(\0oo 和 \xhh)是 ASCII 碼的特殊表示。如果要用八進位制 ASCII 碼錶示一個字元,可以在編碼值前面加一個反斜槓(\)並用單引號括起來。例如,如果編譯器不識別警報字元(\a),可以使用 ASCII 碼來代替:

beep = '\007';

可以省略前面的 0,'\07' 甚至 '\7' 都可以。即使沒有字首 0,編譯器在處理這種寫法時,仍會解釋為八進位制。

從 C90 開始,不僅可以用十進位制、八進位制形式表示字元常量,C 語言還提供了第 3 種選擇——用十六進位制形式表示字元常量,即反斜槓後面跟一個 x 或 X,再加上 1~3 位十六進位制數字。例如,Ctrl+P 字元的 ASCII 十六進位制碼是 10(相當於十進位制的 16),可表示為 '\x10''\x010'。圖 5 列出了一些整數型別的不同進位制形式。

圖 5 int 系列型別的常量寫法示例

使用 ASCII 碼時,注意數字和數字字元的區別。例如,字元 4 對應的 ASCII 碼是 52。'4' 表示字元 4,而不是數值 4。

關於轉義序列,讀者可能有下面 3 個問題。

  • 上面最後一個例子(printf("Gramps sez, \"a \\ is a backslash.\"\n")),為何沒有用單引號把轉義序列括起來?無論是普通字元還是轉義序列,只要是雙引號括起來的字元集合,就無需用單引號括起來。雙引號中的字元集合叫作字串。注意,該例中的其他字元(G、r、a、m、p、s 等)都沒有用單引號括起來。與此類似,printf("Hello!\007\n"); 將列印 Hello! 併發出一聲蜂鳴,而 printf("Hello!7\n"); 則列印 Hello!7。不是轉義序列中的數字將作為普通字元被打印出來。
  • 何時使用 ASCII 碼?何時使用轉義序列?如果要在轉義序列(假設使用 '\f')和 ASCII 碼('\014')之間選擇,請選擇前者(即 '\f')。這樣的寫法不僅更好記,而且可移植性更高。'\f' 在不使用 ASCII 碼的系統中,仍然有效。
  • 如果要使用 ASCII 碼,為何要寫成 '\032' 而不是 032?首先,'\032' 能更清晰地表達程式設計師使用字元編碼的意圖。其次,類似 \032 這樣的轉義序列可以嵌入 C 的字串中,如 printf("Hello!\007\n"); 中就嵌入了 \007

3.4 列印字元

printf() 函式用 %c 指明待列印的字元。前面介紹過,一個字元變數實際上被儲存為 1 位元組的整數值。因此,如果用 %d 轉換說明列印 char 型別變數的值,列印的是一個整數。而 %c 轉換說明告訴 printf() 列印該整數值對應的字元。程式清單 5 演示了列印 char 型別變數的兩種方式。

程式清單 5 charcode.c 程式

/* charcode.c-顯示字元的程式碼編號 */
#include <stdio.h>
int main(void)
{
     char ch;

     printf("Please enter a character.\n");
     scanf("%c", &ch);   /* 使用者輸入字元 */
     printf("The code for %c is %d.\n", ch, ch);

     return 0;
}

執行該程式後,輸出示例如下:

Please enter a character.
C
The code for C is 67.

執行該程式時,在輸入字母后不要忘記按下 Enter 或 Return 鍵。隨後,scanf() 函式會讀取使用者輸入的字元,& 符號表示把輸入的字元賦給變數 ch。接著,printf() 函式列印 ch 的值兩次,第 1 次列印一個字元(對應程式碼中的 %c),第 2 次列印一個十進位制整數值(對應程式碼中的 %d)。注意,printf() 函式中的轉換說明決定了資料的顯示方式,而不是資料的儲存方式(見圖 6)。

圖 6 資料顯示和資料儲存

3.5 有符號還是無符號

有些 C 編譯器把 char 實現為有符號型別,這意味著 char 可表示的範圍是 -128~127。而有些 C 編譯器把 char 實現為無符號型別,那麼 char 可表示的範圍是 0~255。請查閱相應的編譯器手冊,確定正在使用的編譯器如何實現 char 型別。或者,可以查閱 limits.h 標頭檔案。

根據 C90 標準,C 語言允許在關鍵字 char 前面使用 signed 或 unsigned。這樣,無論編譯器預設 char 是什麼型別,signed char 表示有符號型別,而 unsigned char 表示無符號型別。這在用 char 型別處理小整數時很有用。如果只用 char 處理字元,那麼 char 前面無需使用任何修飾符。

四、_Bool 型別

C99 標準添加了 _Bool 型別,用於表示布林值,即邏輯值 true 和 false。因為 C 語言用值 1 表示 true,值 0 表示 false,所以 _Bool 型別實際上也是一種整數型別。但原則上它僅佔用 1 位儲存空間,因為對 0 和 1 而言,1 位的儲存空間足夠了。

程式通過布林值可選擇執行哪部分程式碼。

五、可移植型別:stdint.h 和 inttypes.h

C 語言提供了許多有用的整數型別。但是,某些型別名在不同系統中的功能不一樣。C99 新增了兩個標頭檔案 stdint.h 和 inttypes.h,以確保 C 語言的型別在各系統中的功能相同。

C 語言為現有型別建立了更多型別名。這些新的型別名定義在 stdint.h 標頭檔案中。例如,int32_t 表示 32 位的有符號整數型別。在使用 32 位 int 的系統中,標頭檔案會把 int32_t 作為 int 的別名。不同的系統也可以定義相同的型別名。例如,int 為 16 位、long 為 32 位的系統會把 int32_t 作為 long 的別名。然後,使用 int32_t 型別編寫程式,幷包含 stdint.h 標頭檔案時,編譯器會把 int 或 long 替換成與當前系統匹配的型別。

上面討論的類型別名是精確寬度整數型別(exact-width integer type)的示例。int32_t 表示整數型別的寬度正好是 32 位。但是,計算機的底層系統可能不支援。因此,精確寬度整數型別是可選項。

如果系統不支援精確寬度整數型別怎麼辦?C99 和 C11 提供了第 2 類別名集合。一些型別名保證所表示的型別一定是至少有指定寬度的最小整數型別。這組型別集合被稱為最小寬度型別(minimum width type)。例如,int_least8_t 是可容納 8 位有符號整數值的型別中寬度最小的型別的一個別名。如果某系統的最小整數型別是 16 位,可能不會定義 int8_t 型別。儘管如此,該系統仍可使用 int_least8_t 型別,但可能把該型別實現為 16 位的整數型別。

當然,一些程式設計師更關心速度而非空間。為此,C99 和 C11 定義了一組可使計算達到最快的型別集合。這組型別集合被稱為最快最小寬度型別(fastst minimum width type)。例如,int_fast8_t 被定義為系統中對 8 位有符號值而言運算最快的整數型別的別名。

另外,有些程式設計師需要系統的最大整數型別。為此,C99 定義了最大的有符號整數型別 intmax_t,可儲存任何有效的有符號整數值。類似地,uintmax_t 表示最大的無符號整數型別。順帶一提,這些型別有可能比 long long 和 unsigned long 型別更大,因為 C 編譯器除了實現標準規定的型別以外,還可利用 C 語言實現其他型別。例如,一些編譯器在標準引入 long long 型別之前,已提前實現了該型別。

C99 和 C11 不僅提供可移植的型別名,還提供相應的輸入和輸出。例如,printf() 列印特定型別時要求與相應的轉換說明匹配。如果要列印 int32_t 型別的值,有些定義使用 %d,而有些定義使用 %ld,怎麼辦?C 標準針對這一情況,提供了一些字串巨集來顯示可移植型別。例如,inttypes.h 標頭檔案中定義了 PRId32 字串巨集,代表列印 32 位有符號值的合適轉換說明(如 d 或 l)。程式清單 6 演示了一種可移植型別和相應轉換說明的用法。

程式清單 6 altnames.c 程式

/* altnames.c -- 可移植整數型別名 */
#include <stdio.h>
#include <inttypes.h> // 支援可移植型別
int main(void)
{
     int32_t me32;     // me32是一個32位有符號整型變數

     me32 = 45933945;
     printf("First, assume int32_t is int: ");
     printf("me32 = %d\n", me32);
     printf("Next, let's not make any assumptions.\n");
     printf("Instead, use a \"macro\" from inttypes.h: ");
     printf("me32 = %" PRId32 "\n", me32);

     return 0;
}

該程式最後一個 printf() 中,引數 PRId32 被定義在 inttypes.h 中的 "d" 替換,因而這條語句等價於:

printf("me32 = %" "d" "\n", me32);

在 C 語言中,可以把多個連續的字串組合成一個字串,所以這條語句又等價於:

printf("me32 = %d\n", me32);

下面是該程式的輸出,注意,程式中使用了 \" 轉義序列來顯示雙引號:

First, assume int32_t is int: me32 = 45933945
Next, let's not make any assumptions.
Instead, use a "macro" from inttypes.h: me32 = 45933945

篇幅有限,無法介紹擴充套件的所有整數型別。本節主要是為了讓讀者知道,在需要時可進行這種級別的型別控制。

注意 對 C99/C11 的支援

C 語言發展至今,雖然 ISO 已釋出了 C11 標準,但是編譯器供應商對 C99 的實現程度卻各不相同。一些編譯器仍未實現 inttypes.h 標頭檔案及其相關功能。

六、float、double 和 long double

各種整數型別對大多數軟體開發專案而言夠用了。然而,面向金融和數學的程式經常使用浮點數。C 語言中的浮點型別有 float、double 和 long double 型別。它們與 FORTRAN 和 Pascal 中的 real 型別一致。前面提到過,浮點型別能表示包括小數在內更大範圍的數。浮點數的表示類似於科學記數法(即用小數乘以 10 的冪來表示數字)。該記數系統常用於表示非常大或非常小的數。表 3 列出了一些示例。

表 3 記數法示例

數字 科學記數法 指數記數法
1000000000 1.0×109 1.0e9
123000 1.23×105 1.23e5
322.56 3.2256×102 3.2256e2
0.000056 5.6×10-5 5.6e-5

第 1 列是一般記數法;第 2 列是科學記數法;第 3 列是指數記數法(或稱為 e 記數法),這是科學記數法在計算機中的寫法,e 後面的數字代表 10 的指數。圖 7 演示了更多的浮點數寫法。

圖 7 更多浮點數寫法示例

C 標準規定,float 型別必須至少能表示 6 位有效數字,且取值範圍至少是 10-37~10+37。前一項規定指 float 型別必須能夠表示 33.333333 的前 6 位數字,而不是精確到小數點後 6 位數字。後一項規定用於方便地表示諸如太陽質量(2.0e30 千克)、一個質子的電荷量(1.6e-19 庫侖)或國家債務之類的數字。通常,系統儲存一個浮點數要佔用 32 位。其中 8 位用於表示指數的值和符號,剩下 24 位用於表示非指數部分(也叫作尾數或有效數)及其符號。

C 語言提供的另一種浮點型別是 double(意為雙精度)。double 型別和 float 型別的最小取值範圍相同,但至少必須能表示 10 位有效數字。一般情況下,double 佔用 64 位而不是 32 位。一些系統將多出的 32 位全部用來表示非指數部分,這不僅增加了有效數字的位數(即提高了精度),而且還減少了舍入誤差。另一些系統把其中的一些位分配給指數部分,以容納更大的指數,從而增加了可表示數的範圍。無論哪種方法,double 型別的值至少有 13 位有效數字,超過了標準的最低位數規定。

C 語言的第3種浮點型別是 long double,以滿足比 double 型別更高的精度要求。不過,C 只保證 long double 型別至少與 double 型別的精度相同。

6.1 宣告浮點型變數

浮點型變數的宣告和初始化方式與整型變數相同,下面是一些例子:

float noah, jonah;
double trouble;
float planck = 6.63e-34;
long double gnp;

6.2 浮點型常量

在程式碼中,可以用多種形式書寫浮點型常量。浮點型常量的基本形式是:有符號的數字(包括小數點),後面緊跟 e 或 E,最後是一個有符號數表示 10 的指數。下面是兩個有效的浮點型常量:

-1.56E+12
2.87e-3

正號可以省略。可以沒有小數點(如,2E5)或指數部分(如,19.28),但是不能同時省略兩者。可以省略小數部分(如,3.E16)或整數部分(如,.45E-6),但是不能同時省略兩者。下面是更多的有效浮點型常量示例:

3.14159
.2
4e16
.8E-5
100.

不要在浮點型常量中間加空格:1.56 E+12(錯誤!)

預設情況下,編譯器假定浮點型常量是 double 型別的精度。例如,假設 some 是 float 型別的變數,編寫下面的語句:

some = 4.0 * 2.0;

通常,4.0 和 2.0 被儲存為 64 位的 double 型別,使用雙精度進行乘法運算,然後將乘積截斷成 float 型別的寬度。這樣做雖然計算精度更高,但是會減慢程式的執行速度。

在浮點數後面加上 f 或 F 字尾可覆蓋預設設定,編譯器會將浮點型常量看作 float 型別,如 2.3f 和 9.11E9F。使用 l 或 L 字尾使得數字成為 long double 型別,如 54.3l和4.32L。注意,建議使用 L 字尾,因為字母 l 和數字 1 很容易混淆。沒有後綴的浮點型常量是 double 型別。

C99 標準添加了一種新的浮點型常量格式——用十六進位制表示浮點型常量,即在十六進位制數前加上十六進位制字首(0x 或 0X),用 p 和 P 分別代替 e 和 E,用 2 的冪代替 10 的冪(即,p 計數法)。如下所示:

0xa.1fp10

十六進位制 a 等於十進位制 10,.1f 是 1/16 加上 15/256(十六進位制 f 等於十進位制 15),p10 是 210 或 1024。0xa.1fp10 表示的值是 (10 + 1/16 + 15/256)×1024(即,十進位制 10364.0)。

注意,並非所有的編譯器都支援 C99 的這一特性。

6.3 列印浮點值

printf() 函式使用 %f 轉換說明列印十進位制記數法的 float 和 double 型別浮點數,用 %e 列印指數記數法的浮點數。如果系統支援十六進位制格式的浮點數,可用 a 和 A 分別代替 e 和 E。列印 long double 型別要使用 %Lf%Le%La 轉換說明。給那些未在函式原型中顯式說明引數型別的函式(如,printf())傳遞引數時,C 編譯器會把 float 型別的值自動轉換成 double 型別。程式清單 7 演示了這些特性。

程式清單 7 showf_pt.c 程式

/* showf_pt.c -- 以兩種方式顯示float型別的值 */
#include <stdio.h>
int main(void)
{
     float aboat = 32000.0;
     double abet = 2.14e9;
     long double dip = 5.32e-5;

     printf("%f can be written %e\n", aboat, aboat);
     // 下一行要求編譯器支援C99或其中的相關特性
     printf("And it's %a in hexadecimal, powers of 2 notation\n", aboat);
     printf("%f can be written %e\n", abet, abet);
     printf("%Lf can be written %Le\n", dip, dip);

     return 0;
}

該程式的輸出如下,前提是編譯器支援 C99/C11:

32000.000000 can be written 3.200000e+04
And it's 0x1.f4p+14 in hexadecimal, powers of 2 notation
2140000000.000000 can be written 2.140000e+09
0.000053 can be written 5.320000e-05

該程式示例演示了預設的輸出效果。

6.4 浮點值的上溢和下溢

假設系統的最大 float 型別值是 3.4E38,編寫如下程式碼:

float toobig = 3.4E38 * 100.0f;
printf("%e\n", toobig);

會發生什麼?這是一個上溢(overflow)的示例。當計算導致數字過大,超過當前型別能表達的範圍時,就會發生上溢。這種行為在過去是未定義的,不過現在 C 語言規定,在這種情況下會給 toobig 賦一個表示無窮大的特定值,而且 printf() 顯示該值為 inf 或 infinity(或者具有無窮含義的其他內容)。

當對一個很小的數做除法時,情況更為複雜。回憶一下,float 型別的數以指數和尾數部分來儲存。存在這樣一個數,它的指數部分是最小值,即由全部可用位表示的最小尾數值。該數字是 float 型別能用全部精度表示的最小數字。現在把它除以 2。通常,這個操作會減小指數部分,但是假設的情況中,指數已經是最小值了。所以計算機只好把尾數部分的位向右移,空出第 1 個二進位制位,並丟棄最後一個二進位制數。以十進位制為例,把一個有 4 位有效數字的數(如,0.1234E-10)除以 10,得到的結果是 0.0123E-10。雖然得到了結果,但是在計算過程中卻損失了原末尾有效位上的數字。這種情況叫作下溢(underflow)。C 語言把損失了型別全精度的浮點值稱為低於正常的(subnormal)浮點值。因此,把最小的正浮點數除以 2 將得到一個低於正常的值。如果除以一個非常大的值,會導致所有的位都為 0。現在,C 庫已提供了用於檢查計算是否會產生低於正常值的函式。

還有另一個特殊的浮點值 NaN(not a number 的縮寫)。例如,給 asin() 函式傳遞一個值,該函式將返回一個角度,該角度的正弦就是傳入函式的值。但是正弦值不能大於 1,因此,如果傳入的引數大於 1,該函式的行為是未定義的。在這種情況下,該函式將返回 NaN 值,printf() 函式可將其顯示為 nan、NaN 或其他類似的內容。

浮點數舍入錯誤

給定一個數,加上 1,再減去原來給定的數,結果是多少?你一定認為是 1。但是,下面的浮點運算給出了不同的答案:

/* floaterr.c--演示舍入錯誤 */
#include <stdio.h>
int main(void)
{
    float a,b;

    b = 2.0e20 + 1.0;
    a = b - 2.0e20;
    printf("%f \n", a);

    return 0;
}

該程式的輸出如下:

0.000000        ←Linux系統下的老式gcc
-13584010575872.000000  ←Turbo C 1.5
4008175468544.000000    ←XCode 4.5、Visual Studio 2012、當前版本的gcc

得出這些奇怪答案的原因是,計算機缺少足夠的小數位來完成正確的運算。2.0e20 是 2 後面有 20 個 0。如果把該數加 1,那麼發生變化的是第 21 位。要正確運算,程式至少要儲存 21 位數字。而 float 型別的數字通常只能儲存按指數比例縮小或放大的 6 或 7 位有效數字。在這種情況下,計算結果一定是錯誤的。另一方面,如果把 2.0e20 改成 2.0e4,計算結果就沒問題。因為 2.0e4 加 1 只需改變第 5 位上的數字,float 型別的精度足夠進行這樣的計算。

浮點數表示法

上一個方框中列出了由於計算機使用的系統不同,一個程式有不同的輸出。原因是,根據前面介紹的知識,實現浮點數表示法的方法有多種。為了儘可能地統一實現,電子和電氣工程師協會(IEEE)為浮點數計算和表示法開發了一套標準。現在,許多硬體浮點單元都採用該標準。2011 年,該標準被 ISO/IEC/IEEE 60559:2011 標準收錄。該標準作為 C99 和 C11 的可選項,符合硬體要求的平臺可開啟。floaterr.c 程式的第 3 個輸出示例即是支援該浮點標準的系統顯示的結果。

七、複數和虛數型別

許多科學和工程計算都要用到複數和虛數。C99 標準支援複數型別和虛數型別,但是有所保留。一些獨立實現,如嵌入式處理器的實現,就不需要使用複數和虛數(VCR 晶片就不需要複數)。一般而言,虛數型別都是可選項。C11 標準把整個複數軟體包都作為可選項。

簡而言之,C 語言有 3 種複數型別:float _Complex、double _Complex 和 long double _Complex。例如,float _Complex 型別的變數應包含兩個 float 型別的值,分別表示複數的實部和虛部。類似地,C 語言的3種虛數型別是 float _Imaginary、double _Imaginary 和 long double _Imaginary。

如果包含 complex.h 標頭檔案,便可用 complex 代替 _Complex,用 imaginary 代替 _Imaginary,還可以用 I 代替 -1 的平方根。

為何 C 標準不直接用 complex 作為關鍵字來代替 _Complex,而要新增一個頭檔案(該標頭檔案中把 complex 定義為 _Complex)?因為標準委員會考慮到,如果使用新的關鍵字,會導致以該關鍵字作為識別符號的現有程式碼全部失效。例如,之前的 C99,許多程式設計師已經使用 struct complex 定義一個結構來表示複數或者心理學程式中的心理狀況。讓 complex 成為關鍵字會導致之前的這些程式碼出現語法錯誤。但是,使用 struct _Complex 的人很少,特別是標準使用首字母是下劃線的識別符號作為預留字以後。因此,標準委員會選定 _Complex 作為關鍵字,在不用考慮名稱衝突的情況下可選擇使用 complex。

八、其他型別

現在已經介紹完 C 語言的所有基本資料型別。有些人認為這些型別實在太多了,但有些人覺得還不夠用。注意,雖然 C 語言沒有字串型別,但也能很好地處理字串。

C 語言還有一些從基本型別衍生的其他型別,包括陣列、指標、結構和聯合。儘管後面會詳細介紹這些型別,但是本文的程式示例中已經用到了指標〔指標(pointer)指向變數或其他資料物件位置〕。例如,在 scanf() 函式中用到的字首 &,便建立了一個指標,告訴 scanf() 把資料放在何處。

九、型別大小

如何知道當前系統的指定型別的大小是多少?執行程式清單 8,會列出當前系統的各型別的大小。

程式清單 8 typesize.c 程式

/* typesize.c -- 列印型別大小 */
#include <stdio.h>
int main(void)
{
     /* C99為型別大小提供%zd轉換說明 */
     printf("Type int has a size of %zd bytes.\n", sizeof(int));
     printf("Type char has a size of %zd bytes.\n", sizeof(char));
     printf("Type long has a size of %zd bytes.\n", sizeof(long));
     printf("Type long long has a size of %zd bytes.\n",
               sizeof(long long));
     printf("Type double has a size of %zd bytes.\n",
              sizeof(double));
     printf("Type long double has a size of %zd bytes.\n",
              sizeof(long double));
     return 0;
}

sizeof 是 C 語言的內建運算子,以位元組為單位給出指定型別的大小。C99 和 C11 提供 %zd 轉換說明匹配 sizeof 的返回型別。一些不支援 C99 和 C11 的編譯器可用 %u%lu 代替 %zd

該程式的輸出如下:

Type int has a size of 4 bytes.
Type char has a size of 1 bytes.
Type long has a size of 8 bytes.
Type long long has a size of 8 bytes.
Type double has a size of 8 bytes.
Type long double has a size of 16 bytes.

該程式列出了 6 種類型的大小,你也可以把程式中的型別更換成感興趣的其他型別。注意,因為 C 語言定義了 char 型別是 1 位元組,所以 char 型別的大小一定是 1 位元組。而在 char 型別為 16 位、double 型別為 64 位的系統中,sizeof 給出的 double 是4位元組。在 limits.h 和 float.h 標頭檔案中有型別限制的相關資訊。

順帶一提,注意該程式最後幾行 printf() 語句都被分為兩行,只要不在引號內部或一個單詞中間斷行,就可以這樣寫。

十、小結:基本資料型別

關鍵字:

基本資料型別由 11 個關鍵字組成:int、long、short、unsigned、char、float、double、signed、_Bool、_Complex 和 _Imaginary。

有符號整型:

有符號整型可用於表示正整數和負整數。

  • int ——系統給定的基本整數型別。C 語言規定 int 型別不小於 16 位。
  • short 或 short int ——最大的 short 型別整數小於或等於最大的 int 型別整數。C 語言規定 short 型別至少佔 16 位。
  • long 或 long int ——該型別可表示的整數大於或等於最大的 int 型別整數。C 語言規定 long 型別至少佔 32 位。
  • long long 或 long long int ——該型別可表示的整數大於或等於最大的 long 型別整數。long long 型別至少佔 64 位。

一般而言,long 型別佔用的記憶體比 short 型別大,int 型別的寬度要麼和 long 型別相同,要麼和 short 型別相同。例如,舊 DOS 系統的 PC 提供 16 位的 short 和 int,以及 32 位的 long;Windows 95 系統提供 16 位的 short 以及 32 位的 int 和 long。

無符號整型:

無符號整型只能用於表示零和正整數,因此無符號整型可表示的正整數比有符號整型的大。在整型型別前加上關鍵字 unsigned 表明該型別是無符號整型:unsigned int、unsigned long、unsigned short。單獨的 unsigned 相當於 unsigned int。

字元型別:

可打印出來的符號(如 A、& 和 +)都是字元。根據定義,char 型別表示一個字元要佔用 1 位元組記憶體。出於歷史原因,1 位元組通常是 8 位,但是如果要表示基本字符集,也可以是 16 位或更大。

  • char ——字元型別的關鍵字。有些編譯器使用有符號的 char,而有些則使用無符號的 char。在需要時,可在 char 前面加上關鍵字 signed 或 unsigned 來指明具體使用哪一種型別。

布林型別:

布林值表示 true 和 false。C 語言用 1 表示 true,0 表示 false。

  • _Bool ——布林型別的關鍵字。布林型別是無符號 int 型別,所佔用的空間只要能儲存 0 或 1 即可。

實浮點型別:

實浮點型別可表示正浮點數和負浮點數。

  • float ——系統的基本浮點型別,可精確表示至少 6 位有效數字。
  • double ——儲存浮點數的範圍(可能)更大,能表示比 float 型別更多的有效數字(至少 10 位,通常會更多)和更大的指數。
  • long double ——儲存浮點數的範圍(可能)比 double 更大,能表示比 double 更多的有效數字和更大的指數。

複數和虛數浮點數:

虛數型別是可選的型別。複數的實部和虛部型別都基於實浮點型別來構成:

  • float _Complex
  • double _Complex
  • long double _Complex
  • float _Imaginary
  • double _Imaginary
  • long double _Imaginary

十一、小結:如何宣告簡單變數

1.選擇需要的型別。

2.使用有效的字元給變數起一個變數名。

3.按以下格式進行宣告:

型別說明符 變數名;

型別說明符由一個或多個關鍵字組成。下面是一些示例:

int erest;
unsigned short cash;

4.可以同時宣告相同型別的多個變數,用逗號分隔各變數名,如下所示:

char ch, init, ans;

5.在宣告的同時還可以初始化變數:

float mass = 6.0E24;

原文:C 語言中的基本資料型別

(完)