首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C 語言 EOF 與 feof 深度解析:為什麼 while(!feof(fp)) 是錯的

     編輯:關於C語言

EOF 的真相

#define EOF (-1) // 只是一個 int 常量 -1
  • 文件物理末尾不存在 EOF 字元。
  • fgetc 內部:讀取 1 字節 → 視為 unsigned char → 擴展為 int 返回(高位補 0)。正常數據返回 0~255,不可能為負數。
  • 唯有「讀取失敗(已到末尾)」時,返回 EOF(-1,即 0xFFFFFFFF)。

char 陷阱:誤判二進制文件

char ch;
while ((ch = fgetc(fp)) != EOF) { ... } // 錯誤!

若文件含字節 0xFF:

  1. fgetc 返回 0x000000FF (255)
  2. 賦值給 char ch → 截取低 8 位 0xFF
  3. char 有符號 → 值為 -1
  4. 比較 ch != EOF → -1 != -1 為假 → 誤判為文件結束

修正:接收變數必須定義為 int。

int ch;
while ((ch = fgetc(fp)) != EOF) { ... } // 正確

feof 的機制與經典誤區

標準定義

#define _IOEOF 0x0010
#define feof(fp) ((fp)->_flag & _IOEOF)

feof 只檢查流結構體內的 EOF 標誌位,該標誌只有在「讀取操作因到達末尾而失敗」後才被置位。

錯誤示範

while (feof(fp) == 0) {
    ch = fgetc(fp);
    printf("%0X\n", ch);
}
// 輸出會多印一個 FFFFFFFF

原因:讀完最後一個有效字節後,EOF 標誌尚未置位,迴圈繼續,再次 fgetc 失敗返回 -1 並置位標誌,隨後打印 -1,下輪 feof 才檢測到結束。

正確模式

// 模式一:讀取作為迴圈條件
int ch;
while ((ch = fgetc(fp)) != EOF) {
    printf("%0X\n", ch);
}

// 模式二:先讀後判(較少用)
ch = fgetc(fp);
while (feof(fp) == 0) {
    printf("%0X\n", ch);
    ch = fgetc(fp);
}

符號擴展補充:類型轉換視角

unsigned char ch1 = 0xFF; // 255
char ch2 = 0xFF;          // -1 (有符號)
char ch3 = 0x73;          // 115

int a = ch1; // 0x000000FF = 255 (零擴展)
int b = ch2; // 0xFFFFFFFF = -1 (符號擴展,高位補 1)
int c = ch3; // 0x00000073 = 115 (符號擴展,高位補 0)

規則:無符號類型擴展補 0,有符號類型擴展補符號位。這正是 fgetc 返回 int 且 char 接收會出錯的根源。

總結

  1. EOF 是 int 常量 -1,非文件內容字元。
  2. 讀取函數返回 int,接收變數必須用 int。
  3. feof/ferror 是事後檢查標誌,不可作為迴圈前置條件。
  4. 正確迴圈模式:while ((ch = fgetc(fp)) != EOF) 或 while (fgets(buf, n, fp))。
  5. 二進制文件處理更推薦 fread+返回值判斷。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved