結論:EOF是在頭文件stdio.h中預定義的一個宏,而eof(end of file)是一個與標准輸入/輸出流相關聯的標志位。當文件指針已經指向文件尾且再次嘗試讀取時,eof標志會被設置。同時,某些函數會在讀取到文件尾(即eof標志被設置)時返回EOF作為標識。
另注:
筆者經常會在C進行文件I/O操作時出現文件讀取實際尚未結束(未讀取至文件末尾),但系統顯示已讀取至文件尾的情況。具體原因如下。
在過去的操作系統中,文件以文件存儲占用的扇區數作為文件大小的計數單位,故而如果文件的大小不能恰好填滿存儲文件的最后一個扇區,則需要對該扇區剩余的空間進行填充,過去填充使用的是值為26(0x1a)的字節,也就是某些系統中 Ctrl+Z 的對應碼值,故而在讀取文件過程中,讀取到值26,則系統認為文件已經到達末尾,不再讀取。在 windows 環境下,終端輸入可以使用 Ctrl + z 作為輸入的 EOF 標志,而 linux 環境下,則可使用 Ctrl + d 作為輸入的結束標志。
現在的操作系統開始使用字節作為文件大小的計數單位,但古老的習慣還是被保留下來。為了避免文件讀取過程中存在值為26的數據使得系統誤認為文件結束而停止讀取,可以將文件以二進制文件格式打開。
EOF
EOF常被在程序中用於判斷(文件)緩沖區是否結束,實際在頭文件 stdio.h 中定義。
可以看到EOF是一個頭文件中預定義的宏,其值為 -1 。也就是說,在程序中使用的EOF實際為一個預定義的常數。而許多的函數會在讀取至文件末尾或出現錯誤時,會返回EOF,作為處理狀態的一種描述,如下文的getchar.
getchar(getchar C++ Reference)
函數聲明:int getchar(void);
函數功能:當函數讀取成功時,會返回成功讀取的字符數據(轉化為 int 類型),若失敗,則返回值為EOF,也就是上文說的值為 -1 的宏定義。
可以從上面的介紹中看到,函數除返回EOF外,還會設置標准輸入( stdin )的 eof 標志/error標志,可供feof或ferror函數使用。也就是說,EOF(宏定義)與eof標志並不是同一個東西。
getchar函數在頭文件stdio.h中定義,具體實現如下:
顯然,讀取字符數據並指向下一個待讀取的數據操作是由 *stdin->_ptr++ 來實現的,而返回 EOF 以及將上文提及的error標志和eof標志則是由函數_filbuf實現。
從上面資料可以得到結論:
(1)對一般的文件/輸入流,存在一個指向待讀取數據位置的內部的指針(如上面的stdin->_ptr),每次讀取數據完成該內部指針會移動指向下一個待讀取數據;
(2)文件/輸入流還存在兩個特殊的標志 eof 和 error ,它們可以分別被函數feof和ferror處理,當文件讀取至文件末尾或出現錯誤時,相應的標志位eof/error會被設置;
(3)一些函數在發生錯誤或讀取至文件末尾時,會返回EOF,其為值為 -1 的宏,同時設置文件/輸入流的某些標志;
feof( feof C++ Reference)
函數聲明:int feof(FILE *stream); //stream為對應的文件流的標志
函數功能:會檢查與文件對應流的eof( end of file )標志是否被設置,如果被設置則返回非零值,如未被設置,則返回0.
注意:feof函數只檢查eof標志是否被設置,其本身並不會設置eof標志,設置eof標志的是試圖進行數據讀取的操作。
示例:
1 #include<stdio.h> 2 3 int main(void) 4 { 5 FILE *ptr = fopen("a.txt","r"); 6 7 if(!ptr) 8 { 9 printf("打開文件失敗!\n"); 10 return -1; 11 } 12 13 char ch; 14 int count = 0 ; 15 16 while(!feof(ptr)) //檢測到EOF標志則停止 17 { 18 count++; 19 ch = fgetc(ptr); 20 printf("%c",ch); 21 } 22 printf("%5d",count); 23 printf("\n"); 24 25 fclose(ptr); 26 return 0; 27 }
示例代碼讀取的a.txt的內容為"12".代碼會逐字節顯示文件的內容(19、20行),以及讀取的次數(18、22行)。
執行結果下圖所示:
(1)EOF標志未被設置時,feof函數會返回0,eof標志被設置后,feof返回非零值;
(2)每次讀取成功后,指向文件流內部的指針會順序移動讀取的字數個字節(對文本來說),這樣使得內部指針總是指向待讀取的下一個字符;
(3)執行流程 : feof返回值為0,第一次循環,ch = ‘1’,count = 1,流內部的位置指針指向‘2’;feof返回值為0,第二次循環,ch = ‘2’,count = 2,流內部的位置指針指向文件末尾,但此時EOF並未被設置;feof返回值仍為0,第三次循環,會試圖訪問文件的末尾,count = 3,eof 標志被設置,下一次的feof返回值為非0值,故而結束循環;(筆者在CodeBlocks12.13中調試時,第三次循環時ch的值為-1,即為EOF,printf並沒有將其顯示至控制台)
文件流內部存在標志讀取位置的內部指針,該位置指針指向文件尾並不會設置對應文件流的eof 標志,只有當該位置指針指向文件尾,並再次試圖進行順序讀操作時,才會設置eof標志。
EOF為一個定義的宏常量,而eof標志為與文件/輸入流相關的一個標志,當位置指針已指向文件末尾並再次試圖讀取輸入時,會設置eof標志,同時為了表明發生的情況,函數一般會返回EOF用來表示文件讀取至末尾或發生錯誤。