#define EOF (-1) // 只是一個 int 常量 -1
fgetc 內部:讀取 1 字節 → 視為 unsigned char → 擴展為 int 返回(高位補 0)。正常數據返回 0~255,不可能為負數。EOF(-1,即 0xFFFFFFFF)。char ch;
while ((ch = fgetc(fp)) != EOF) { ... } // 錯誤!
若文件含字節 0xFF:
fgetc 返回 0x000000FF (255)char ch → 截取低 8 位 0xFFchar 有符號 → 值為 -1ch != EOF → -1 != -1 為假 → 誤判為文件結束修正:接收變數必須定義為 int。
int ch;
while ((ch = fgetc(fp)) != EOF) { ... } // 正確
#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 接收會出錯的根源。
EOF 是 int 常量 -1,非文件內容字元。int,接收變數必須用 int。feof/ferror 是事後檢查標誌,不可作為迴圈前置條件。while ((ch = fgetc(fp)) != EOF) 或 while (fgets(buf, n, fp))。fread+返回值判斷。