天天看點

getchar的傳回值問題

getchar的傳回值問題

許多初學者都習慣用 char 型變量接收 getchar、getc,fgetc 等函數的傳回值,其實這麼做是不對的,并且隐含着足以緻命的錯誤。

getchar 等函數的傳回值類型都是 int 型,當這些函數讀取出錯或者讀完檔案後,會傳回 EOF。EOF 是一個宏,标準規定它的值必須是一個 int 型的負數常量。通常編譯器都會把 EOF 定義為 -1。

問題就出在這裡,使用 char 型變量接收 getchar 等函數的傳回值會導緻對 EOF 的辨認出錯,或者錯把好的資料誤認為是 EOF,或者把 EOF 誤認為是好的資料。

例如: int c;

while ( (c = fgetc(fp)) != EOF )

 {

 putchar(c);

}

如上例所示,我們很多時候都需要先用一個變量接收 fgetc 等函數的傳回值,然後再用這個變量和 EOF 比較,判斷是否已經讀完檔案。上面這個例子是正确的,把 c 定義為 int 型保證了它能正确接收 fgetc 傳回的 EOF,進而保證了這個比較的正确性。

但是,如果把 c 定義為 char 型,則會導緻意想不到的後果。

首先,因為 fgetc 等函數的傳回值是 int 型的,當指派給 char 型變量時,會發生降級,進而導緻資料截斷。

例如: | 十進制 | int | char |

 | 10 | 00 00 00 0A | 0A |

| -1 | FF FF FF FF | FF |

 | -2 | FF FF FF FE | FE |

在此,我們假設 int 和 char 分别是 32 位和 8 位的。由上表可得,從 int 型到 char 型,損失了 3 個位元組的資料。而當我們要拿 char 型和 int 型比較的時候,char 型會自動更新為 int 型。char 型更新為 int 型後的值會因為它到底是 signed char 還是 unsigned char 而有所不同。不幸的是,如果我們沒有使用 signed 或者 unsigned 來修飾 char,那麼我們無從知曉 char 到底是指 unsigned char 還是指 signed char,因為這是由編譯器決定的。不過,無論 char 是 signed 的也好,unsigned 的也罷,都不能改變使用 char 型變量接收 fgetc 等函數的傳回值是錯誤的這個事實。唯一能改變的是該錯誤導緻的後果。前面我們說了,char 型和 int 型比較時,char 會自動更新為 int,下面我們來看看 signed char 和 unsigned char 在轉換成 int 後,它們的值有什麼不同:--------------------------------------- | char | unsigned | signed ||-------|---------------|-------------|

| 10 | 00 00 00 0A | 00 00 00 0A | | FF | 00 00 00 FF | FF FF FF FF | | FE | 00 0000 FE | FF FF FF FE | ---------------------------------------由上表可知,當 char 是 unsigned 的時候,其轉換為 int 後的值是正數。也就是說,假如我們把 c 定義為 char 型變量,而編譯器預設 char 為 unsigned char,那麼以下表達式将永遠成立。 (c = fgetc(fp)) != EOF 也就是說以下循環是一個死循環。 while ( (c = fgetc(fp)) !=EOF ) { putchar(c); } 讀到這裡,可能有些讀者朋友會說:“那麼我明确把 c 定義為 signed char 型的就沒問題了吧!”很遺憾,就算把 c 定義為 signed char,仍然是錯誤的。假設 fgetc 等函數讀到一個位元組的值為 FF,那麼傳回值就是 00 00 00 FF。把這個值指派給 c 後, c 的值變成 FF。然後 c 的值為了和 EOF 比較,會自動更新為 int 型的值,也就是 FF FF FF FF。進而導緻以下表達式不成立。 (c = fgetc(fp)) != EOF 也就是說以下循環在沒有讀完檔案的情況下提前退出。 while ( (c = fgetc(fp)) !=EOF ) { putchar(c); } 綜上所述,使用 char 型變量接收 fgetc 等函數的傳回值是錯誤的,我們必須使用 int 型變量接收這些函數的傳回值,然後判斷接收到的值是否 EOF。隻有判斷發現該傳回值并非 EOF,我們才可以把該值指派給 char 型變量。 同理,C++ 中,用 char 型變量接收 cin.get() 的傳回值也是錯誤的。不過,把 char 型變量當作參數傳遞給 cin.get 則是正确的。例如: char c = cin.get(); // 錯誤,理由同上 char c; cin.get(c); // 正确

上一篇: Another Server