La risposta è che fflush(stream)
è solo formalmente definito per i flussi di output, quindi fflush(stdout)
è OK, ma non lo è fflush(stdin)
.
Lo scopo di fflush(stream)
è far sì che il sistema operativo svuota i buffer del file sottostante. Per un esempio di un uso legittimo, gli studenti hanno spesso problemi come “la mia richiesta non viene visualizzata!” Se fanno qualcosa di simile:
printf("Enter a number: ");
Tuttavia, scoprono che questo funziona bene:
printf("Enter a number:\n");
Ovviamente, non vogliono una nuova riga dopo il loro prompt, quindi hanno un po 'di problemi.
Il motivo è che l'uscita su stdout
viene memorizzata nel buffer dal sistema operativo e il comportamento predefinito è (spesso) solo per scrivere effettivamente l'output sul terminale quando viene rilevata una nuova riga. Aggiunta di un fflush(stdout)
dopo la printf()
risolve il problema:
printf("Enter a number: ");
fflush(stdout);
Ora, lavorando per analogia, le persone spesso pensano che fflush(stdin)
dovrebbe eliminare qualsiasi ingresso inutilizzato, ma se ci pensate un po 'che non ha molto senso . Che cosa significa "svuotare" un buffer di input? Dove viene "svuotato" a? Se svuoti un buffer di output, l'output viene inviato al file sottostante o al terminale, dove finirà comunque, ma dove sarebbe lo input "alla fine finire comunque"? Non c'è modo di saperlo! Quale dovrebbe essere il comportamento se i dati del flusso di input provengono da un file o una pipe o un socket? Non è a tutti chiaro per flussi di input quale dovrebbe essere il comportamento di fflush()
, ma è molto chiaro per i flussi di output in tutti i casi. Quindi, fflush()
è definito solo per i flussi di output.
Il motivo per cui l'uso errato di fflush(stdin)
è diventato luogo comune è che, molti anni fa, alcuni sistemi operativi fatto implementare uno schema in cui ha lavorato come molti si aspettavano, scartando ingresso inutilizzato. Microsoft DOS è un buon esempio. Sorprendentemente, le versioni moderne di Linux implementano anche fflush()
per i flussi di input.
La cosa giusta da fare con l'ingresso terminale indesiderato "extra" è semplicemente leggerlo e non fare nulla con esso. Questo è quasi facile come chiamare fflush(stdin)
, funziona ovunque e non si basa su un comportamento formalmente indefinito.
Il norma C dice:
If flusso indica un flusso di output o un flusso di aggiornamento, in cui l'operazione più recente non era ingresso, la funzione fflush provoca alcun dato scritte per quel flusso da consegnare all'ambiente ospite da scrivere sul file; in caso contrario, il comportamento non è definito.
POSIX says (anche demanda espressamente C standard):
If flusso indica un flusso di output o un flusso di aggiornamento, in cui l'operazione più recente non era ingresso, fflush() deve provocare tutti i dati non scritti per tale flusso da scrivere il file, ...
Ma la Linux manpage dice:
0.123.
Per i flussi di output, fflush() impone una scrittura di tutti i dati memorizzati nello spazio utente per l'output specificato o il flusso di aggiornamento tramite la funzione di scrittura sottostante del flusso. Per i flussi di input, fflush() scarta qualsiasi dato memorizzato nel buffer che è stato recuperato dal file sottostante, ma non è stato consumato dall'applicazione. Lo stato di apertura del flusso non è influenzato.
'fflush (stdin);' è un comportamento non definito. Non farlo, non copiarlo da quelli che lo fanno. http://stackoverflow.com/questions/2979209/using-fflushstdin – Joe
@chrk Non sono d'accordo con l'aggiunta del tag 'linux'. Nulla nel post di OP è specifico per Linux. – chux
@chrk Sì, ripristina. I tag sono per il soggetto del Post, non per il tipo di persone che cercano. – chux