簡體   English   中英

`fgetc()` 可能返回 `EOF` 的所有原因是什么?

[英]What are all the reasons `fgetc()` might return `EOF`?

當然fgetc()文件結束或發生輸入錯誤時返回EOF ,但這就是全部嗎?這是否意味着沒有更多數據可用?

FILE *inf = ...;
int ch;
while ((ch = fgetc(inf)) != EOF) {
  ;
}
if (feof(inf)) puts("End-of-file");
else if (ferror(inf)) puts("Error");
else puts("???");

使用feof(), ferror()進行測試是否足夠?

注意:這里的EOF是一個計算結果為負數的宏int ,通常是-1 不是end-of-file的同義詞。

我發現了一些這個問題很接近的問題,但沒有一個能列舉出所有的可能性。

這是我可以回答我自己的問題嗎? .

僅此而已,這是否意味着沒有更多可用數據?

不,還有更多EOF方法。
EOF並不一定意味着不再有數據 - 這取決於。

C 庫列出了fgetc()返回EOF的 3 種情況。

If the end-of-file indicator for the stream is set, or if the stream is at end-of-file, the end-of-file indicator for the stream is set and the fgetc function returns EOF . 否則, fgetc function 從 stream 指向的輸入 stream 返回下一個字符。 如果發生讀取錯誤,則設置 stream 的錯誤指示器,並且fgetc function 返回EOF C17dr § 7.21.7.1 3

回想一下每個stream ,像stdin一樣,有一個文件結束指示器錯誤指示器

  • stream 剛遇到文件尾
    (最常見)已嘗試獲取更多數據,但沒有。

  • stream 的文件結束指示符已設置
    stream 首先檢查其文件結束指示器 如果它看到指標已設置,則返回EOF 沒有嘗試查看是否存在更多數據。 某些類型的流將報告EOF ,但數據將在之前的EOF報告之后到達。 在與clearerr()一樣清除文件結束指示符之前,返回保持為EOF 示例示例

  • 輸入錯誤
    檢查 stream錯誤指示器。 然而,function 由於某種原因無法讀取文件結尾以外的數據。 一個常見的例子是fputc(stdin) 通常輸入錯誤是持久的。 有些不是。 可能有更多數據可用。 常見的策略是結束輸入。

     // Example where ferror() is true, yet fgetc() does not return EOF FILE *inf = stdin; printf("end-of-file:%d error:%d\n", feof(inf), ferror(inf)); printf("fputc():%d\n", fputc('?', inf)); // EOF reported printf("end-of-file:%d error:%d\n", feof(inf), ferror(inf)); printf("fgetc():%d\n", fgetc(inf)); // User typed in `A`, 'A' reported printf("end-of-file:%d error:%d\n", feof(inf), ferror(inf));

Output

end-of-file:0 error:0
fputc():-1
end-of-file:0 error:1
fgetc():65
end-of-file:0 error:1

ferror()為真時,這並不意味着錯誤剛剛發生,只是在過去的某個時間。

其他案例

  • 由於不正確地保存為char而導致的明顯EOF
    fgetc()返回一個int ,其值在unsigned char范圍內, EOF - 一個負值。 fgetc()讀取字符代碼 255,但在char簽名的系統上將其保存為char時,通常會導致char具有與EOF相同的值,但不會出現文件結束。

     FILE *f = fopen("t", "w"); fputc(EOF & 255, f); fclose(f); f = fopen("t", "r"); char ch = fgetc(f); // Should be int ch printf ("%d %d\n", ch == EOF, ch); printf("end-of-file:%d error:%d\n", feof(f), ferror(f)); fclose(f);

Output

1 -1  // ch == EOF !
end-of-file:0 error:0
  • UCHAR_MAX == UINT_MAX的系統。 罕見
    (我只在一些較舊的圖形處理器中遇到過這種情況,仍然是 C 允許的。)在這種情況下, fgetc()可能會讀取int范圍之外的unsigned char ,因此在 function 返回時將其轉換為EOF 因此fgetc()返回一個恰好等於EOF的字符代碼。 這主要是 C 歷史上的一個奇怪現象。 主要處理的一種方法是:

     while ((ch = fgetc(inf));= EOF && !feof(inf) && !ferror(inf)) { ; }

很少需要這種迂腐的代碼。

  • 未定義的行為
    當然,當 UB 發生時,一切皆有可能。

     FILE * f = fopen("Some_non_existent_file", "r"); // Should have tested f == NULL here printf("%d\n", fgetc(f) == EOF); // Result may be 1

一種處理來自fgetc()的返回的可靠方法。

FILE *inf = ...;
if (inf) {  // Add test
  int ch; // USE int !

  // Pedantic considerations, usually can be ignored
  #if UCHAR_MAX > INT_MAX
    clearerr(inf); // Clear history of prior flags
    while ((ch = fgetc(inf)) != EOF && !feof(inf) && !ferror(inf)) {
      ;
    }
  #else
    while ((ch = fgetc(inf)) != EOF) {
      ;
    }
  #endif

  if (feof(inf)) puts("End-of-file");
  else puts("Error");

如果代碼需要在end-of-fileerror之后查找數據,請調用clearerr()並重復if()塊。

EOF 不一定意味着“沒有更多數據”的另一種情況是(而不是“是”)讀取磁帶。 一個磁帶上可以有多個文件,每個文件的結尾都標有 EOF。 當您遇到 EOF 時,您使用clearerr(fp)重置文件 stream 上的 EOF 和錯誤狀態,然后您可以繼續讀取磁帶上的下一個文件。 然而,磁帶(在大多數情況下)已經走上了渡渡鳥的道路,所以這幾乎不再重要了。

這是一個晦澀的原因:

0x1A上,以文本模式讀取字節 0x1A 會導致 EOF。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM