2015-09-18 7 views
7

Io uso sempre questo approccioQual è il modo migliore per controllare EOF e l'errore di fgetc()?

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

Per quanto mi sembra più leggibile e robusto. Ma ad una risposta dei miei link, chux commentato che

se (feof (fp)) è più robusto di int c; while ((c = fgetc (fp))! = EOF)

Come

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

è più robusto rispetto alla prima versione. Quindi quale versione dovrei usare? Per favore, spiegami perché quella versione è migliore.

EDIT

In questione Why is “while (!feof (file))” always wrong? ci ha chiesto perché feof() in loop di controllo sempre sbagliato. Ma controllare feof() se le condizioni sono corrette? La spiegazione è apprezzabile.

+4

Utilizzare la prima versione. Il secondo non è "più robusto" ma richiede molto più codice. Inoltre non riesce a verificare la presenza di una condizione di errore. – fuz

+0

@user - No, il modo C++ corretto è 'while (cin >> c)', e assolutamente ** not ** 'mentre (! Cin.eof())'. Vedi [Perché isostream :: eof all'interno di una condizione di ciclo considerata errata] (http://stackoverflow.com/questions/5605125/why-is-iostreameof-inside-a-loop-condition-considered-wrong) –

+4

@Kninnug It non è un duplicato di quella domanda. – ashiquzzaman33

risposta

4

solito ingresso programma di loop come questo:

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 */ 
} 

Si dovrebbe in genere non utilizzare una condizione di loop come questo:

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

o

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

Poiché si rompe quando un Si è verificato un errore IO. In questo caso, fgetc restituisce EOF ma il flag di fine file non è impostato. Il tuo codice potrebbe entrare in un ciclo infinito in quanto una condizione di errore persiste di solito fino a quando non viene intrapresa un'azione esterna.

Il modo corretto è verificare il risultato di fgetc(): se è uguale a EOF, in genere è possibile interrompere la lettura di ulteriori dati sia in caso di errore IO che di condizione di fine file, in genere non è possibile leggere ulteriori dati. Dovresti quindi controllare se si è verificato un errore e prendere le misure appropriate.

+7

L'OP ha richiesto una * spiegazione *. –

+1

Non è una risposta inutile (che dovrebbe quindi essere downvoted), ma in realtà non risponde a ciò che l'OP sta cercando. – edmz

+0

@KarolyHorvath Soddisfatto? – fuz

1

Il miglioramento suggerito non è migliore, anche meno robusto.

Come spiegato here, entra in un ciclo infinito se si verifica un errore di lettura (senza eof). In tal caso, feof restituirà 0 mentre fgetc restituisce EOF.

La versione non presenta questo problema.

Inoltre, la tua versione è più breve, meno complessa e più o meno standard.

+0

@ Ashiquzzaman: non è un duplicato. –

4

La questione dei test per una condizione di errore è venuto a causa di un corner case in C.

fgetc() restituisce un int. I valori sono compresi nell'intervallo unsigned char e EOF, (un numero negativo).

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

Eppure C permette unsigned char di avere una gamma più ampia rispetto al numero positivo di int. La conversione da unsigned char a int ha un comportamento definito dall'implementazione che può comportare la conversione di un valore unsigned char in un valore negativo int e uno che corrisponde a EOF.

Tali piattaforme sono rare e non nel flusso principale del 2015. La maggior parte avrà UCHAR_MAX <= INT_MAX e lo stile sopra è in genere utilizzato. Dubbi che queste piattaforme diventeranno sempre comuni a causa della quantità di codice, come sopra, che si basa su EOF distinto da unsigned char convertito in int.

codice dovrebbe avere bisogno per gestire il caso raro in cui UCHAR_MAX > INT_MAX, quindi

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 
} 

Il riferimento popolare in while (!feof (file)) always wrong? evidenzia il codice di errore fa spesso utilizzando i risultati di fgetc(in) prima di controllare per i problemi. Entrambi i codici sopra controllano le condizioni di errore prima di utilizzare il risultato di fgetc().


Il secondo codice gestisce tutte le situazioni, tra cui quelli che si possono applicare solo a un computer seduto in un qualche mucchio di spazzatura lungo dimenticato. Il primo è molto più comune.