Vastaus tähän on, että fflush(stream) on muodollisesti määritelty vain ulostulovirroille, joten fflush(stdout) on OK, mutta fflush(stdin) ei ole.

Vastauksen fflush(stream) tarkoituksena on saada käyttöjärjestelmä huuhtelemaan mahdolliset puskurit taustalla olevaan tiedostoon. Esimerkkinä laillisesta käytöstä: Opiskelijoilla on usein ongelmia, kuten ”kehotteeni ei tule näkyviin!”, jos he tekevät jotain sellaista kuin:

printf("Enter a number: ");

Mutta he huomaavat, että tämä toimii ihan hyvin:

printf("Enter a number:\n");

Ei tietenkään haluta rivinvaihtoa kehotteen perään, joten heillä on pieni ongelma.

Syy tähän on se, että käyttöjärjestelmä puskuroi stdout:n ulostulon ja oletuskäyttäytyminen on (usein) se, että ulostulo kirjoitetaan terminaaliin oikeasti vasta, kun uusi rivi tulee. Lisäämällä fflush(stdout) printf():n jälkeen ratkaisee ongelman:

printf("Enter a number: ");fflush(stdout);

Nyt, analogisesti ajatellen, ihmiset ajattelevat usein, että fflush(stdin):n pitäisi hylätä kaikki käyttämättömät syötteet, mutta jos asiaa miettii hieman, siinä ei ole paljon järkeä. Mitä tarkoittaa syöttöpuskurin ”huuhteleminen”? Mihin se ”huuhdellaan”? Jos tyhjennät tulostuspuskurin, tuloste lähetetään taustalla olevaan tiedostoon tai päätelaitteeseen, jonne se päätyisi lopulta joka tapauksessa, mutta minne tuloste ”päätyisi lopulta joka tapauksessa”? Sitä ei voi mitenkään tietää! Miten pitäisi toimia, jos tulovirran tiedot tulevat tiedostosta, putkesta tai socketista? Syöttövirtojen osalta ei ole lainkaan selvää, miten fflush():n pitäisi käyttäytyä, mutta lähtövirtojen osalta se on hyvin selvää kaikissa tapauksissa. Siksi fflush() on määritelty vain ulostulovirroille.

Syy siihen, miksi fflush(stdin):n virheellinen käyttö yleistyi, on se, että monta vuotta sitten muutamat käyttöjärjestelmät toteuttivat järjestelmän, jossa se toimi niin kuin monet odottivat, eli käyttämättömän syötteen hylkääminen. Microsoft DOS on hyvä esimerkki. Yllättäen myös nykyaikaiset Linux-versiot toteuttavat fflush():n syöttövirroille.

Oikea tapa toimia ”ylimääräisen” ei-toivotun päätelaitesyötteen kanssa on yksinkertaisesti lukea se ja olla tekemättä sille mitään. Tämä on melkein yhtä helppoa kuin kutsua fflush(stdin), toimii kaikkialla, eikä luota muodollisesti määrittelemättömään käyttäytymiseen.

C-standardi sanoo:

Jos stream osoittaa tulostusvirtaan tai päivitysvirtaan, jossa viimeisin operaatio ei ollut syöttö, fflush-funktio saa aikaan sen, että kaikki kyseisen virran kirjoittamattomat tiedot toimitetaan isäntäympäristöön tiedostoon kirjoitettavaksi; muutoin käyttäytyminen on määrittelemätöntä.

POSIX sanoo (poikkeaa myös eksplisiittisesti C-standardista):

Jos stream osoittaa tulostusvirtaan tai päivitysvirtaan, jossa viimeisin operaatio ei ollut sisäänsyöttö, fflush()-funktio saa aikaan sen, että kaikki kyseisen virran kirjoittamattomat tiedot kirjoitetaan tiedostoon, …

Mutta Linuxin manpage sanoo:

Lähtövirtojen osalta fflush() pakottaa kirjoittamaan kaiken käyttäjäavaruuden puskuroidun datan kyseiselle lähtö- tai päivitysvirralle virran taustalla olevan kirjoitusfunktion kautta. Syöttövirroissa fflush() hylkää kaikki puskuroidut tiedot, jotka on haettu taustalla olevasta tiedostosta, mutta joita sovellus ei ole käyttänyt. Virran avoin tila ei vaikuta siihen.

Vastaa

Sähköpostiosoitettasi ei julkaista.