Domanda

Quindi, una rapida ricerca su Google per fflush(stdin) per cancellare la memoria di ingresso rivela numerosi siti web di avvertimento contro l'uso di esso. Eppure questo è esattamente come il mio professore di CS ha insegnato la classe per farlo.

Quanto male sta usando fflush(stdin)? Devo davvero astenersi dall'uso di esso, anche se il mio professore lo sta utilizzando e sembra funzionare senza problemi?

È stato utile?

Soluzione

Semplice: questo è un comportamento indefinito, poiché fflush è destinato a essere chiamato su un flusso di output. Questo è un estratto dalla serie C:

int fflush (FILE * ostream);

punti ostream ad un flusso di output o un flusso di aggiornamento in cui più recente operazione non era ingresso, la funzione fflush provoca qualsiasi scritta dati relativi a tale flusso da consegnare per l'ambiente host da scrivere al file; altrimenti, il comportamento non è definito.

Quindi non è una questione di "quanto male" questo è. fflush(stdin) è chiaramente sbagliato , e non deve usarla, mai .

Altri suggerimenti

Conversione di commenti in una risposta -. Ed estendendoli dal momento che le riappare periodicamente emissione

standard C e POSIX congedo fflush(stdin) come comportamento non definito

Il POSIX , standard C e C ++ per fflush() esplicitamente affermano che il comportamento è indefinito, ma nessuno di loro impedisce un sistema da definirla.

ISO / IEC 9899: 2011 - la C11 standard - dice:

§7.21.5.2 La funzione fflush

Se ¶2 punti stream ad un flusso di output o di un flusso di aggiornamento in cui l'operazione più recente non è stato in ingresso, la funzione fflush causa di tutti i dati non scritti per quel flusso da consegnare al ambiente host da scrivere il file; in caso contrario, non è definito il comportamento.

POSIX per lo rimette alla serie C, ma lo fa marcare il testo come estensione C.

[CX] Per per leggere, se il file non è già a EOF, e il file è capace di cercare un aperto flusso, il file di offset della descrizione file aperto sottostante è fissato alla posizione di file del flusso , e tutti i caratteri spinto indietro sul flusso da ungetc() o ungetwc() che non sono in seguito stati letti dal flusso deve essere scartata (senza ulteriore modifica del file di offset).

Si noti che i terminali non sono in grado di cercare; né sono pipe o socket.

Microsoft definisce il comportamento di fflush(stdin)

Microsoft e lo Studio runtime di Visual definisce il definire il comportamento di fflush() su un flusso di input .

Se il flusso è aperto per l'input, fflush cancella il contenuto del buffer.

MM note :

Cygwin è un esempio di una piattaforma abbastanza comune su cui fflush(stdin) non cancella l'ingresso.

Questo è il motivo per cui questa versione risposta del mio note 'Microsoft e il runtime di Visual Studio' - se si utilizza una libreria di runtime non Microsoft C, il comportamento che si vede dipende da quella libreria.

la documentazione e la pratica di Linux sembrano contraddirsi a vicenda

Sorprendentemente, Linux documenta nominalmente il comportamento di fflush(stdin) troppo, e anche lo definisce allo stesso modo (miracolo di miracoli).

Per i flussi di ingresso, rigetti fflush() dati bufferizzati che è stato prelevato dal file sottostante, ma non è stato consumato dall'applicazione.

Rimango un po 'perplesso e sorpreso la documentazione di Linux dicendo che fflush(stdin) funzionerà. Nonostante ciò il suggerimento, ma la maggior parte di solito non funziona su Linux. Ho appena controllato la documentazione su Ubuntu 14.04 LTS; si dice quello citato sopra, ma empiricamente, non funziona - almeno quando il flusso di ingresso è un dispositivo non seekable come un terminale

.

demo-fflush.c

#include <stdio.h>

int main(void)
{
    int c;
    if ((c = getchar()) != EOF)
    {
        printf("Got %c; enter some new data\n", c);
        fflush(stdin);
    }
    if ((c = getchar()) != EOF)
        printf("Got %c\n", c);

    return 0;
}

uscita Esempio

$ ./demo-fflush
Alliteration
Got A; enter some new data
Got l
$

Questa uscita è stata ottenuta sia su Ubuntu 14.04 LTS e Mac OS X 10.11.2. Per la mia comprensione, contraddice quello che dice il manuale di Linux. Se l'operazione fflush(stdin) funzionato, avrei dovuto digitare una nuova riga di testo per ottenere informazioni per la seconda getchar() da leggere.

Dato quello che dice lo standard POSIX, forse è necessaria una dimostrazione migliore, e la documentazione di Linux dovrebbe essere chiarito.

demo-fflush2.c

#include <stdio.h>

int main(void)
{
    int c;
    if ((c = getchar()) != EOF)
    {
        printf("Got %c\n", c);
        ungetc('B', stdin);
        ungetc('Z', stdin);
        if ((c = getchar()) == EOF)
        {
            fprintf(stderr, "Huh?!\n");
            return 1;
        }
        printf("Got %c after ungetc()\n", c);
        fflush(stdin);
    }
    if ((c = getchar()) != EOF)
        printf("Got %c\n", c);

    return 0;
}

uscita Esempio

Si noti che /etc/passwd è un file ricercabile. Su Ubuntu, la prima linea si presenta così:

root:x:0:0:root:/root:/bin/bash

In Mac OS X, le prime 4 righe apparire come:

##
# User Database
# 
# Note that this file is consulted directly only when the system is running

In altre parole, v'è il commento nella parte superiore del file /etc/passwd Mac OS X. Le linee non commento conformi al layout normale, quindi la voce root è:

root:*:0:0:System Administrator:/var/root:/bin/sh

Ubuntu 14.04 LTS:

$ ./demo-fflush2 < /etc/passwd
Got r
Got Z after ungetc()
Got o
$ ./demo-fflush2
Allotrope
Got A
Got Z after ungetc()
Got B
$

Mac OS X 10.11.2:

$ ./demo-fflush2 < /etc/passwd
Got #
Got Z after ungetc()
Got B
$

I ignora il comportamento di Mac OS X (o almeno sembra ignorare) il fflush(stdin) (quindi non segue POSIX su questo tema). I corrisponde Linux comportamento al comportamento POSIX documentato, ma la specifica POSIX è molto più attento a quello che dice - si specifica un file in grado di cercare, ma i terminali, ovviamente, non supportano cercano. E 'anche molto meno utile rispetto alla specifica di Microsoft.

Sommario

Microsoft documenta il comportamento di fflush(stdin). A quanto pare, funziona come documentato sulla piattaforma Windows, utilizzando il compilatore nativo di Windows e librerie di supporto runtime C.

Nonostante documentazione al contrario, non funziona su Linux quando l'ingresso standard è un terminale, ma sembra seguire specifiche POSIX che è molto più accuratamente formulata. Secondo lo standard C, è definito il comportamento di fflush(stdin). POSIX aggiunge la qualificazione 'meno che il file di input è ricercabile', quale un terminale non è. Il comportamento non è lo stesso di Microsoft.

Di conseguenza, codice portabile non usa fflush(stdin). Codice che è legato alla piattaforma di Microsoft può usarlo e funzionerà, ma attenzione i problemi di portabilità.

POSIX modo per scarti terminale di ingresso non letto da un file descrittore

Il metodo standard POSIX scartare informazioni non letto da un descrittore file di terminale (al contrario di un flusso di file come stdin) è illustrato a Come posso dati non letti filo da una coda di input tty su un sistema Unix . Tuttavia, che sta operando al di sotto del livello di I / O standard biblioteca.

Secondo lo standard, fflush può essere utilizzato solo con buffer di uscita, e ovviamente non stdin è uno. Tuttavia, le biblioteche alcuni di serie C, e forniscono l'uso di fflush(stdin) come estensione . In questo caso si può utilizzare, ma che interesserà la portabilità, in modo da non essere più in grado di utilizzare qualsiasi libreria standard C conforme agli standard sulla terra e si aspettano gli stessi risultati.

POSIX :

Per per la lettura, se il file non è già a EOF un aperto ruscello, e il file è uno in grado di cercare, il file di offset della descrizione file aperto sottostante è fissato alla posizione del file del flusso, e tutti i caratteri spinto indietro sulla stream ungetc () o ungetwc () che non sono in seguito stati letti dal flusso devono essere Dis cardato (senza ulteriore modifica del file di offset).

Nota che il terminale non è in grado di cercare.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top