2012-09-09 18 views

Odpowiedz

27

Każdy strumień ma wewnętrzną flagę, która wskazuje, czy rozmówca próbował już odczytać koniec pliku. feof zwraca tę flagę. Flaga nie wskazuje, czy aktualna pozycja pliku jest końcem pliku, tylko czy poprzedni odczyt próbował odczytać koniec pliku.

Jako przykład przyjrzyjmy się temu, co się dzieje podczas czytania pliku zawierającego dwa bajty.

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 

Dlatego Poniżej znajduje się źle sposobem korzystania EOF podczas czytania pliku:

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

ze względu na sposób feof prac, flaga EOF jest tylko ustaw raz getc próbuje odczytać koniec pliku. getc następnie zwróci EOF, która jest , a nie znakiem, a konstrukcja pętli powoduje, że putchar jest próbą zapisania go na zewnątrz, powodując błąd lub wynik czyszczenia.

Każdy C standardowe metody wprowadzania biblioteki zwraca informację o powodzeniu lub awaria: getc zwraca wartość szczególną EOF gdyby próbował odczytać przeszłości końca pliku, lub jeśli wystąpił błąd podczas odczytu. Specjalna wartość to to samo dla końca pliku i błędu, i tu pojawia się właściwy sposób użycia feof: można go użyć do rozróżnienia sytuacji końca pliku i błędu .

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"); 
} 

Jest inny wewnętrzny flaga dla FILE obiektów do sytuacji błędu: ferror. Często łatwiej jest przetestować błędy niż "nie koniec pliku". idiomatycznym sposób na zapoznanie się z pliku w C jest tak:

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

(Niektóre sprawdzanie błędów zostało pomijana z przykładów tutaj, dla zwięzłości.)

Funkcja feof jest dość rzadko przydatna.

+2

Prosty i poprawny :-) – cnicutar

+1

Przepraszam, podekscytowałem się i nieco go rozszerzyłem. –

+0

To jeszcze lepiej – cnicutar

3

Możesz lepiej zrozumieć, jak działa feof, wiedząc, jak to jest zaimplementowane. Oto uproszczona wersja, w jaki sposób biblioteka stdio 7th Edition Unix implementuje feof. Nowoczesne biblioteki są bardzo podobne, dodając kod oferujący bezpieczeństwo wątków, zwiększoną wydajność i czystszą implementację.

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); 

}

biblioteki stdio utrzymuje każdego pliku strukturę zawierającą wewnętrzną buforze wskazanym przez _base.Bieżący znak w buforze jest wskazywany przez _ptr, a liczba dostępnych znaków jest zawarta w _cnt. Makro getc, które jest podstawą wielu funkcji wyższego poziomu, takich jak scanf, próbuje zwrócić znak z bufora. Jeśli bufor jest pusty, zadzwoni pod numer _filbuf, aby go wypełnić. _filbuf z kolei zadzwoni pod numer read. Jeśli read zwróci 0, co oznacza, że ​​nie będzie już dostępnych żadnych danych, _filbuf ustawi flagę _IOEOF, którą sprawdza za każdym razem, gdy wywołuje ją, aby zwrócić wartość true.

Jak możesz zrozumieć z powyższego, feof zwróci true po raz pierwszy podczas próby odczytania znaku po końcu pliku (lub funkcja biblioteki próbuje w twoim imieniu). Ma to subtelne konsekwencje w zachowaniu różnych funkcji. Rozważ plik zawierający pojedynczy znak: cyfrę 1. Po przeczytaniu tej postaci z getc, feof zwróci false, ponieważ flaga _IOEOF jest rozbrojona; nikt jeszcze nie próbował czytać poza końcem pliku. Ponowne wywołanie getc spowoduje wywołanie read, ustawienie flagi _IOEOF, a to spowoduje, że feof zwróci true. Jednak po odczytaniu numeru z tego samego pliku przy użyciu fscanf("%d", &n), feof natychmiast zwróci wartość true, ponieważ fscanf spróbuje odczytać dodatkowe cyfry liczby całkowitej.

Powiązane problemy