<stdio.h>,通常展開為 -1(int 型別)。文本模式下,資料以 ASCII 字元碼(0~255)儲存。**文本流中不可能出現 -1**,因此 getc()、fgetc() 返回 EOF (-1) 可唯一標識「檔案結束」或「讀取錯誤」。
二進制模式下,資料按原始位元組儲存,**位元組值 0xFF (255) 合法存在**。若讀取函數返回 int,0xFF 擴展為 255,與 EOF (-1) 不衝突;但若直接將返回值賦給 char(有號),0xFF 會變成 -1,**誤判為 EOF**,導致提前終止讀取。
ANSI C 提供 int feof(FILE *fp):
適用於文本與二進制檔案。
// 文本檔案:可用 EOF 或 feof
while ((ch = fgetc(fp)) != EOF) { ... }
// 二進制檔案:必須用 feof 搭配返回值檢查
while (1) {
size_t n = fread(buf, 1, sizeof(buf), fp);
if (n == 0) {
if (feof(fp)) break; // 正常結束
if (ferror(fp)) handle(); // 錯誤
}
process(buf, n);
}
// 通用模式(推薦):檢查讀取函數返回值,再用 feof/ferror 區分原因
int ch;
while ((ch = fgetc(fp)) != EOF) { ... }
if (feof(fp)) puts("正常讀完");
else if (ferror(fp)) perror("讀取錯誤");
// 錯誤!feof() 只在「嘗試讀取越界後」才置位
while (!feof(fp)) {
fread(...); // 最後一次讀完後 feof 仍為 0,再進迴圈一次 → 處理垃圾數據
}
鐵律: 先嘗試讀取,根據返回值判斷是否成功,**失敗後**再用 feof()/ferror() 區分原因。
| 場景 | 判斷結束方式 | 備註 |
|---|---|---|
| 文本檔案逐字元讀取 | fgetc() == EOF 或 feof() | EOF 為 -1,文本流無衝突 |
| 文本檔案逐行讀取 | fgets() == NULL | 返回 NULL 表示結束或錯誤 |
| 二進制檔案塊讀取 | fread() 返回值 < 要求數 + feof()/ferror() | **絕不可**直接用 EOF |
| 二進制檔案逐位元組 | fgetc() == EOF + 檢查 feof() | 需確保變數為 int 而非 char |
牢記:「EOF 是文本流的約定俗成,feof() 才是檔案系統的官方標誌。」二進制處理永遠以「讀取函數返回值」為準,輔以 feof/ferror 診斷。