2012-09-09 21 views

回答

27

每個FILE流都有一個內部標誌,指示調用者是否嘗試讀取已超過文件末尾的內容。 feof返回該標誌。該標誌並不表示當前文件位置是否作爲文件的結尾,而僅表示前一次讀取是否嘗試讀取文件末尾。

作爲一個例子,讓我們通讀一個包含兩個字節的文件時會發生什麼。

f = fopen(filename, "r"); // file is opened 
assert(!feof(f));   // eof flag is not set 
c1 = getc(f);    // read first byte, one byte remaining 
assert(!feof(f));   // eof flag is not set 
c2 = getc(f);    // read second byte, no bytes remaining 
assert(!feof(f));   // eof flag is not set 
c3 = getc(f);    // try to read past end of the file 
assert(feof(f));   // now, eof flag is set 

這就是爲什麼以下是通過文件讀取時使用EOF的錯誤方式:

f = fopen(filename, "r"); 
while (!feof(f)) { 
    c = getc(f); 
    putchar(c); 
} 

因爲這樣feof作品,檔案結尾的標誌僅設置一次getc 嘗試讀取文件的末尾。 getc將返回EOF,這是 不是一個字符,並且循環構造導致putchar嘗試將其寫入 out,導致錯誤或垃圾輸出。

每個C標準庫輸入法返回成功或失敗 的指示:如果它試圖讀到文件的 結束,或者如果有一個錯誤,而讀getc返回特殊值EOF。特殊值是 對於文件結束和錯誤是相同的,這就是使用 feof的正確方法的地方:您可以使用它來區分文件結束和錯誤 的情況。

f = fopen(filename, "r"); 
c = getc(f); 
if (c == EOF) { 
    if (feof(f)) 
     printf("it was end-of-file\n"); 
    else 
     printf("it was error\n"); 
} 

沒有爲FILE對象錯誤的情況下另一個內部標誌: ferror。測試錯誤通常更清楚,而不是「不結束文件」。 通過在C文件中讀取一個習慣的方法是這樣的:

f = fopen(filename, "r"); 
while ((c = getc(f)) != EOF) { 
    putchar(c); 
} 
if (ferror(f)) { 
    perror(filename): 
    exit(EXIT_FAILURE); 
} 
fclose(f); 

(一些錯誤檢查已從例子省略掉這裏,爲簡潔起見。)

feof功能是相當很少有用。

+2

簡單而正確:-) – cnicutar

+1

對不起,興奮和擴大了一下。 – 2012-09-09 08:42:33

+0

它更好 – cnicutar

3

通過了解它的實施方式,您可以更好地瞭解feof的工作原理。以下是第7版Unix stdio庫如何實現feof的簡化版本。現代庫非常相似,增加了提供線程安全性,提高效率和更清晰實現的代碼。

extern struct _iobuf { 
    char *_ptr; 
    int  _cnt; 
    char *_base; 
    char _flag; 
    char _file; 
} _iob[_NFILE]; 

#define _IOEOF 020 

#define feof(p)   (((p)->_flag&_IOEOF)!=0) 

#define getc(p)   (--(p)->_cnt>=0? *(p)->_ptr++&0377:_filbuf(p)) 

int 
_filbuf(FILE *iop) 
{ 

    iop->_ptr = iop->_base; 
    iop->_cnt = read(fileno(iop), iop->_ptr, BUFSIZ); 
    if (iop->_cnt == 0) { 
      iop->_flag |= _IOEOF; 
      return(EOF); 
    } 
    return(*iop->_ptr++ & 0377); 

}

stdio庫與每個文件維護包含由_base指出的內部緩衝器的結構。緩衝區中的當前字符由_ptr指出,可用字符數包含在_cnt中。 getc宏是許多高級功能的基礎,如scanf,它會嘗試從緩衝區中返回一個字符。如果緩衝區爲空,它將調用_filbuf來填充它。 _filbuf又會撥打read。如果read返回0,表示沒有更多數據可用,則_filbuf將設置_IOEOF標誌,並在每次調用它時返回true以檢查。

從上面可以理解,feof將在您第一次嘗試讀取超過文件末尾的字符(或庫函數代表您嘗試)時返回true。這對各種功能的行爲有微妙的影響。考慮一個包含單個字符的文件:數字1。在讀取getc的字符後,feof將返回false,因爲_IOEOF標誌未設置;沒有人試圖讀過文件的末尾。再次調用getc將導致read的調用,_IOEOF標誌的設置,這將導致feof返回true。但是,在使用fscanf("%d", &n)讀取同一文件中的數字後,feof將立即返回true,因爲fscanf將嘗試讀取整數的其他數字。