C 教材:為什麼 getchar() 要儲存到 int 資料型態的變數?

如果是第一次閱讀,那麼先看看就好,也許學了第D講之後再來複習。

在第一版的 mycat0.c 中, 我們說 getchar() 從標準輸入裝置讀進一個字元。 以前學過,字元的資料含量是 1-byte,但 int 的資料含量是 4-byte。 為什麼不宣告 cchar 就好了? 為什麼要使用資料型態比較長的 int

char 資料型態只用一個 byte 來記錄資料。 它相當於 1-byte 或 8-bit 的整數資料型態,故只能記錄 -128 到 127 的整數。 雖然標準的 ASCII 碼只有 0 到 127,也就是 MSB = 0 的情形。 但是現在許多的字碼都用到 MSB = 1 的位元組 (bit pattern), 例如 Latin-1 和 Big-5 碼。 所以,代表檔案結束的 EOF 就不能與所有這些碼衝突。 否則,讀到這個字碼,就會務以為檔案結束。 因此,最安全的做法就是,使用比 char 更大的整數資料型態來記錄 EOF。 這就是為什麼我們宣告 c 的資料型態是 int 而非 char。 利用

printf("%d\n", EOF);
我們看到 EOF 只是一個符號常數,它就是 -1。 如果將 c 宣告成 char, 它的位元組就是 11111111 (二補數記錄 -1)。 這個位元組與 extended ASCII 碼的 255 號是一樣的, 電腦將無法分辨它們的不同 (電腦其實只認得位元組)。 於是,如果輸入的檔案中有 extended ASCII 255 字元 (y 上面加兩點), 就會誤判為檔案結束。 如果將 c 宣告成 int, 則若讀到普通字元,例如 A 的字碼,c 的位元組就是
00000000000000000000000001000001
例如讀到 extended ASCII 255 號字元,c 的位元組就是
00000000000000000000000011111111
若讀到 EOF,則c 的位元組就是
11111111111111111111111111111111
這就絕對不會混淆。

雖然 getchar 讀進來一個字元的碼, 但是它確先將這個碼轉換成 int 型態,再拿進來交給 cputchar 就反過來。 它如果得到一個 char 型態的資料,那沒問題。 但是如果它得到一個 int 型態的資料,就像前面那個程式, 則它會只取最小的 8 個 bits 送出去。 這就是為什麼可以寫 putchar(c);

此外,我們再做一個練習,來瞭解 UNIX 對於純文字檔案的處理。 首先,用一個編輯器,編輯一個新檔案。例如名叫 a.txt。 裡面只寫一列 5 個字元:a 空格 b 空格 c

a b c
不要按 Enter 就儲存檔案。另外寫一個簡單的程式
#include <stdio.h>
 
main () {
   int i, c;
   for (i=0; i<10; ++i) {
       c = getchar();
       printf("%d ", c);
    }
    putchar('\n');
}

這個程式固定從 stdin 讀 10 個字元進來,但是輸出它們的數值。 編譯後執行。在我的機器上,得到
shell% a.out < a.txt
97 32 98 32 99 10 -1 -1 -1 -1
其中 97 是 a 的 ASCII 號碼,32 是空格的 ASCII 號碼, 10 是 ASCII 的 LF (LineFeed) 碼,-1 是 EOF。 有此可見:
  1. UNIX 的編輯器,會自動在檔案結束前,加一個 Enter (LF 碼)。
  2. 如果檔案已經結束了,再繼續讀字元進來,會一再地得到 EOF。

習題

  1. 怎樣使用 putchar 輸出一個 LF 碼?
  2. putchar(65);putchar(321); 各輸出什麼符號? 為什麼會這樣?(提示:321 = 256 + 65。)
[BCC16-C]
單維彰 (2000/03/30) ---
[Prev] [Next] [Up]