getchar的返回值問題

2021-05-28 06:16:46 字數 2337 閱讀 3025

getchar的返回值問題

許多初學者都習慣用 char 型變數接收 getchar、getc,fgetc 等函式的返回值,其實這麼做是不對的,並且隱含著足以致命的錯誤。

getchar 等函式的返回值型別都是 int 型,當這些函式讀取出錯或者讀完檔案後,會返回 eof。eof 是乙個巨集,標準規定它的值必須是乙個 int 型的負數常量。通常編譯器都會把 eof 定義為 -1。

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

例如: int c; /* 正確。應該使用 int 型變數接收 fgetc 的返回值 */

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

如上例所示,我們很多時候都需要先用乙個變數接收 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 /* c 的值永遠為正數,而標準規定 eof 為負數 */ 也就是說以下迴圈是乙個死迴圈。 while ( (c = fgetc(fp)) !=eof ) 讀到這裡,可能有些讀者朋友會說:「那麼我明確把 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 /* 讀到值為 ff 的字元,誤認為 eof */ 也就是說以下迴圈在沒有讀完檔案的情況下提前退出。 while ( (c = fgetc(fp)) !=eof ) 綜上所述,使用 char 型變數接收 fgetc 等函式的返回值是錯誤的,我們必須使用 int 型變數接收這些函式的返回值,然後判斷接收到的值是否 eof。只有判斷發現該返回值並非 eof,我們才可以把該值賦值給 char 型變數。 同理,c++ 中,用 char 型變數接收 cin.get() 的返回值也是錯誤的。不過,把 char 型變數當作引數傳遞給 cin.get 則是正確的。例如: char c = cin.get(); // 錯誤,理由同上 char c; cin.get(c); // 正確

ExecuteNonQuery 返回值問題

關於sqldatacommand.executenonquery 方法 msdn曰 可以使用executenonquery執行編錄操作 例如查詢資料庫的結構或建立諸如表等的資料庫物件 或通過執行 update insert 或 delete 語句更改資料庫中的資料。雖然executenonquery...

返回值優化問題

近來看到小李子寫了篇blog,題目為返回值優化。文章如下。return integer left.i right.i 建立乙個臨時物件並返回他,不會呼叫析構函式,效率高。interger tmp left.i right.i return tmp 建立了區域性物件,有析構函式。這裡感覺有些詭異。於是...

thinkphp CURD 返回值問題

thinkphp的資料寫入操作使用add方法,使用示例如下 user m user 例項化user物件 data name thinkphp data email thinkphp gmail.com result user add data 操作完成後如果寫入結果 result資料非法則返回fal...