2014-04-07 22 views
14

Sono molto nuovo alla programmazione in C e sto cercando di capire come funziona davvero fflush(stdin).Cosa fa fflush (stdin) nella programmazione in C?

Nell'esempio seguente, fflush(stdin) cancella tutto il buffer o cancella quello inserito dopo il terzo elemento? Quello che voglio dire è che l'utente inserisce il numero di conto, lo spazio, il nome, lo spazio, l'equilibrio. È vero che da questo momento in poi, qualunque cosa entri dall'utente verrà lavata con fflush(stdin)? e stdin non sarà vuoto.

Perché dico che è perché entra in un ciclo while e inizia a scrivere sul file di testo.

La mia seconda domanda è se Ctrl-Z dirà al sistema operativo di smettere di chiedere all'utente di inserire l'input?

printf("Enter the account name and balance. (separated by spaces)\n"); 
    printf("Enter EOF to end input. (Ctrl-Z)\n"); 
    printf("? "); 
    scanf("%d%s%lf", &account, name, &balance); 
    fflush(stdin); 

    // write account, name and balance into file with fprintf 
    while (!feof(stdin)) 
    { 
    //fflush(stdin); 
    fprintf(cfPtr, "%d %s %.2f\n", account, name, balance); 
    printf("? "); 
    scanf("%d%s%lf", &account, name, &balance); 
    } 

    fclose(cfPtr); 
+12

'fflush (stdin);' è un comportamento non definito. Non farlo, non copiarlo da quelli che lo fanno. http://stackoverflow.com/questions/2979209/using-fflushstdin – Joe

+0

@chrk Non sono d'accordo con l'aggiunta del tag 'linux'. Nulla nel post di OP è specifico per Linux. – chux

+0

@chrk Sì, ripristina. I tag sono per il soggetto del Post, non per il tipo di persone che cercano. – chux

risposta

15

fflush(stdin) richiama il comportamento non definito.

fflush() è definito solo per i flussi di output. Non dovresti farlo.


In Unix, Ctrl-Z invia un segnale TSTP (SIGTSTP) che di default causa il processo di sospendere l'esecuzione.

21

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.

+3

Potrebbe essere utile notare che questo (Linux che fornisce una definizione per il comportamento indefinito in altri modi) è un'estensione specifica dell'implementazione e dovrebbe essere evitato da persone che sono interessate al codice portatile. –