Het antwoord hierop is dat fflush(stream)
alleen formeel is gedefinieerd voor uitvoerstromen, dus fflush(stdout)
is OK, maar fflush(stdin)
niet.
Het doel van fflush(stream)
is om het besturingssysteem eventuele buffers te laten doorspoelen naar het onderliggende bestand. Voor een voorbeeld van een legitiem gebruik, studenten hebben vaak problemen zoals “mijn prompt verschijnt niet!” als ze iets doen als:
printf("Enter a number: ");
Ze vinden echter dat dit prima werkt:
printf("Enter a number:\n");
Natuurlijk willen ze geen newline na hun prompt, dus ze hebben een beetje een probleem.
De reden hiervoor is dat de uitvoer naar stdout
wordt gebufferd door het OS en het standaard gedrag is (vaak) om de uitvoer pas echt naar de terminal te schrijven als er een newline wordt aangetroffen. Het toevoegen van een fflush(stdout)
na de printf()
lost het probleem op:
printf("Enter a number: ");fflush(stdout);
Nu, naar analogie werkend, denken mensen vaak dat fflush(stdin)
alle ongebruikte invoer moet weggooien, maar als je er een beetje over nadenkt is dat niet erg logisch. Wat betekent het om een invoerbuffer “door te spoelen”? Waar wordt hij naartoe “gespoeld”? Als je een uitvoerbuffer doorspoelt, wordt de uitvoer naar het onderliggende bestand of de terminal gestuurd, waar het uiteindelijk toch terecht zou komen, maar waar zou invoer “uiteindelijk toch terechtkomen”? Er is geen manier om dat te weten! Wat zou het gedrag moeten zijn als de gegevens van de invoerstroom afkomstig zijn van een bestand of een pijp of een socket? Het is helemaal niet duidelijk voor input streams wat het gedrag van fflush()
zou moeten zijn, maar het is in alle gevallen heel duidelijk voor output streams. Vandaar dat fflush()
alleen is gedefinieerd voor uitvoerstromen.
De reden waarom het foutieve gebruik van fflush(stdin)
gemeengoed is geworden, is dat vele jaren geleden een paar besturingssystemen wel een regeling implementeerden waarbij het werkte zoals veel mensen verwachtten, het weggooien van ongebruikte invoer. Microsoft DOS is een goed voorbeeld. Verrassend genoeg implementeren moderne versies van Linux ook fflush()
voor invoerstromen.
Het juiste om te doen met “extra” ongewenste terminalinvoer is om het gewoon te lezen en er niets mee te doen. Dit is bijna net zo gemakkelijk als het aanroepen van fflush(stdin)
, werkt overal, en vertrouwt niet op formeel ongedefinieerd gedrag.
De C-standaard zegt:
Als stream wijst naar een uitvoerstream of een update stream waarin de meest recente bewerking geen invoer was, zorgt de fflush-functie ervoor dat alle ongeschreven gegevens voor die stream aan de hostomgeving worden geleverd om naar het bestand te worden geschreven; anders is het gedrag ongedefinieerd.
POSIX zegt (ook expliciet afgeweken van C-standaard):
Als stream wijst naar een uitvoerstream of een update-stream waarin de meest recente bewerking geen invoer was, zal fflush() ervoor zorgen dat alle ongeschreven gegevens voor die stream naar het bestand worden geschreven, …
Maar de Linux manpage zegt:
Voor uitvoer streams, forceert fflush() een schrijven van alle user-space gebufferde data voor de gegeven uitvoer of update stream via de onderliggende schrijffunctie van de stream. Voor invoerstromen verwijdert fflush() alle gebufferde gegevens die zijn opgehaald van het onderliggende bestand, maar nog niet zijn gebruikt door de toepassing. De open status van de stream blijft onveranderd.