2015-09-18 13 views
7

Zawsze używam tego podejściaJaki jest lepszy sposób sprawdzenia EOF i błąd fgetc()?

int c; 
while ((c = fgetc(fp))!=EOF) 
{ 
    printf("%c", c); 
} 

Ponieważ wydaje mi się bardziej czytelne i trwałe. Ale do odpowiedzi kopalni link, chux skomentował, że

if (feof (FP)) jest bardziej wytrzymałe niż int c; (EOF (C = fgetc (FP))! =)

jako

while(1) 
    { 
     c = fgetc(fp); 
     if (feof(fp)) 
     { 
      break ; 
     } 
     printf("%c", c); 
    } 

natomiast jest bardziej wytrzymałe niż w pierwszej wersji. Więc jakiej wersji powinienem użyć? Proszę wyjaśnij mi, dlaczego ta wersja jest lepsza.

EDIT

W pytaniu Why is “while (!feof (file))” always wrong? nie zapytał dlaczego feof() w pętli sterowania zawsze źle. Ale sprawdzanie feof() w jeśli warunek we właściwy sposób jest zawsze błędny? Wyjaśnienie jest znaczące.

+4

Użyj pierwszej wersji. Drugi nie jest "bardziej wytrzymały", ale wymaga znacznie więcej kodowania. Nie sprawdza również pod kątem błędu. – fuz

+0

@user - Nie, właściwym sposobem C++ jest 'while (cin >> c)', i absolutnie ** nie ** 'while (! Cin.eof())'. Zobacz [Dlaczego isostream :: eof w pętli warunku jest uważany za nieprawidłowy] (http://stackoverflow.com/questions/5605125/why-is-iostreameof-inside-a-loop-condition-considered-wrong) –

+4

@Kninnug It nie jest duplikatem tego pytania. – ashiquzzaman33

Odpowiedz

4

zwykle wejście programu pętle tak:

int c; 

while ((c = fgetc(fp)) != EOF) { 
    /* do something with c here */ 
} 

/* check if EOF came from an end-of-file or an error */ 
if (ferror(fp)) { 
    /* error handling here */ 
} 

Należy generalnie nie używać warunku pętli tak:

while (!feof(fp)) { 
    /* do stuff */ 
} 

lub

for (;;) { 
    c = fgetc(fp); 
    if (feof(fp)) 
     break; 
} 

Ponieważ ta łamie gdy Wystąpił błąd IO. W tym przypadku fgetc zwraca EOF, ale flaga końca pliku nie jest ustawiona. Twój kod może wprowadzić nieskończoną pętlę, ponieważ stan błędu zwykle utrzymuje się, dopóki nie zostanie podjęte działanie zewnętrzne.

Właściwy sposób to sprawdzenie wyniku : Jeśli jest równy EOF, zwykle można przerwać czytanie dalszych danych, ponieważ zarówno w przypadku błędu IO, jak i stanu końca pliku, zwykle nie jest możliwe czytaj dalsze dane. Powinieneś wtedy sprawdzić, czy wystąpił błąd i podjąć odpowiednie działania.

+7

PO poprosił o * wyjaśnienie *. –

+1

To nie jest bezużyteczna odpowiedź (która powinna być następnie obniżona), ale tak naprawdę nie odpowiada na to, czego szukają PO. – edmz

+0

@KarolyHorvath Satisfied? – fuz

1

Sugerowana poprawa nie jest lepsza, nawet mniej odporna.

Jak wyjaśniono here, wchodzi w nieskończoną pętlę, jeśli wystąpi błąd odczytu (bez eof). W takim przypadku feof zwróci 0, podczas gdy fgetc powróci EOF.

Twoja wersja nie ma tego problemu.

Poza tym twoja wersja jest krótsza, mniej skomplikowana i prawie standardowa.

+0

@Ashiquzzaman: To nie jest duplikat. –

4

Kwestia testów dla stanu błędu wpadł powodu corner case w C.

fgetc() zwraca int. Jego wartości mieszczą się w zakresie unsigned char i EOF (pewna liczba ujemna).

int ch; 
while ((ch = fgetc(fp)) != EOF) { 
    // do something with ch 
} 
if (ferror(fp)) Handle_InputError(); 
if (feof(fp)) Handle_EndOffFile(); // Usually nothing special 

Jeszcze C pozwala unsigned char mieć szerszy zakres niż pozytywne liczby int. Konwersja wartości unsigned char do int ma zdefiniowane implementację, która może spowodować przekształcenie wartości na wartość - i taką, która odpowiada EOF.

Takie platformy są rzadkie, a nie w głównym strumieniu 2015 roku. Większość będzie mieć UCHAR_MAX <= INT_MAX, a powyższy styl jest zazwyczaj używany. Wątpliwe, czy platformy te staną się powszechne ze względu na ilość kodu, podobną do powyższej, która opiera się na EOF w odróżnieniu od unsigned char przekonwertowanej na int.

kod powinien trzeba obsłużyć rzadki przypadek, gdy UCHAR_MAX > INT_MAX, następnie

int c; 
for (;;) 
{ 
    c = fgetc(file); 
    if (c == EOF) { 
     if (feof(file)) break; 
     if (ferror(file)) break; 
     // fall through if both if's fail. 
    } 
    // do stuff with c 
} 

Popularna odniesienia w while (!feof (file)) always wrong? pasemkami kod błędu często sprawia wykorzystaniem wyników fgetc(in) przed sprawdzeniem problemów. Oba powyższe kody sprawdzają, czy nie wystąpiły błędy, zanim użyjemy wyniku z fgetc().


Drugi kod obsługuje wszystkie sytuacje, w tym te, które mogą dotyczyć tylko komputera znajdującego się na dawno zapomnianej kupie. Pierwsza jest znacznie bardziej powszechna.

Powiązane problemy