第1章之編程練習心得20140704

有些錯誤非得自己犯過了纔會記得住,非得自己理解了分析了才記得住。比如說用getchar(),fgetc()之類的函數來接收字符時,需要一個變量暫存,而且還要判斷是否讀到EOF,這個在 C陷阱與缺陷 裏面看到過,現在用到又忽略了。我們習慣於用char ch;while( ( c = getchar() ) != EOF ){}  來接收數據。這樣是存在問題的,雖然getchar等是接收字符,但是它的返回值卻是int型,爲什麼呢?因爲EOF在stdio中定義爲-1,不同於任何一個字符。負數在計算機中的存儲形式爲2的補碼,那麼-1 就是 0xFFFFFFFF了。char型肯定無法容納所有可能的字符(字符包括字母,數字,符號,特別是還有漢字!!),先看看字符的可能長度:

1.ASCII編碼中,1個英文字符存儲需要1個字節,

2.GB2312或GBK編碼中,一個漢字字符存儲需要2個字節,

3.UTF-8編碼中,一個英文字符存儲需要1個字節,一個漢字字符需要3到4個字節。

4.UTF-16編碼中,英文和漢字都需要2個字節。

5.UTF-32編碼中,任何字符都需要4個字節。

這下大家應該清楚了吧,不要以爲字符都是一個字節的。


特別是無法容納下EOF,來討論下char  ch會帶來什麼隱患:

1.假設你輸入了一個2個字節的字符吧,0x3CFF,我也不知道代表什麼,那麼getchar返回0x3CFF,截取低字節給ch,ch=0xFF,然後ch要與EOF比較,ch會擴展爲32位。

如果編譯器認爲ch是有符號型的,ch就被擴展爲0XFFFFFFFF,這下可好,誤認爲是EOF了,while循環跳出,提前停止輸入。

2.假設真的碰到了EOF吧,截取爲FF給ch,如果編譯器認爲ch是無符號型的,ch就被擴展爲0x000000FF,這樣永遠也見不到EOF了!陷入死循環。

3.那爲什麼我偏偏使用了char ch,但是沒出問題呢?完全是巧合,許多編譯器對上述表達式的實現並不正確,的確對getchar的返回值做了截斷處理,但是它們在比較表達式中並不是比較c與EOF,而是比較getchar的函數返回值與EOF,編譯器如果這樣,那麼就能正常“運行”了。

正確的聲明:

#include <stdio.h>
int main()
{
    int c;    /* 改成:int c 就正確了 */
 
    while( ( c = getchar() ) != EOF )
    {
        putchar( c );
    }
 
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章