La réponse à cette question est que fflush(stream)
n’est formellement définie que pour les flux de sortie, donc fflush(stdout)
est OK, mais fflush(stdin)
ne l’est pas.
Le but de fflush(stream)
est de faire en sorte que le système d’exploitation chasse tous les tampons vers le fichier sous-jacent. Pour un exemple d’utilisation légitime, les étudiants ont souvent des problèmes comme « mon invite n’apparaît pas ! » s’ils font quelque chose comme :
printf("Enter a number: ");
Pourtant, ils trouvent que cela fonctionne très bien :
printf("Enter a number:\n");
Bien sûr, ils ne veulent pas de nouvelle ligne après leur invite, donc ils ont un peu de problème.
La raison en est que la sortie vers stdout
est mise en mémoire tampon par l’OS et que le comportement par défaut est (souvent) de n’écrire réellement la sortie sur le terminal que lorsqu’une nouvelle ligne est rencontrée. L’ajout d’un fflush(stdout)
après le printf()
résout le problème:
printf("Enter a number: ");fflush(stdout);
Maintenant, en travaillant par analogie, les gens pensent souvent que fflush(stdin)
devrait jeter toute entrée non utilisée, mais si vous y réfléchissez un peu, cela n’a pas beaucoup de sens. Qu’est-ce que cela signifie de « flush » un tampon d’entrée ? Vers où est-il « vidé » ? Si vous videz un tampon de sortie, la sortie est envoyée vers le fichier sous-jacent ou le terminal, où elle finira de toute façon par aboutir, mais où l’entrée « finira de toute façon » ? Il n’y a aucun moyen de le savoir ! Quel devrait être le comportement si les données du flux d’entrée proviennent d’un fichier, d’un pipe ou d’un socket ? Ce n’est pas du tout clair pour les flux d’entrée quel devrait être le comportement de fflush()
, mais c’est très clair pour les flux de sortie dans tous les cas. Par conséquent, fflush()
n’est défini que pour les flux de sortie.
La raison pour laquelle l’utilisation erronée de fflush(stdin)
est devenue courante est que, il y a de nombreuses années, quelques systèmes d’exploitation ont effectivement mis en œuvre un schéma où il fonctionnait comme beaucoup de gens s’y attendaient, en rejetant les entrées inutilisées. Microsoft DOS en est un bon exemple. Étonnamment, les versions modernes de Linux implémentent également fflush()
pour les flux d’entrée.
La bonne chose à faire avec l’entrée « supplémentaire » non désirée du terminal est simplement de la lire et de ne rien en faire. C’est presque aussi facile que d’appeler fflush(stdin)
, cela fonctionne partout et ne repose pas sur un comportement formellement indéfini.
Le standard C dit :
Si stream pointe vers un flux de sortie ou un flux de mise à jour dans lequel l’opération la plus récente n’était pas une entrée, la fonction fflush fait en sorte que toute donnée non écrite pour ce flux soit livrée à l’environnement hôte pour être écrite dans le fichier ; sinon, le comportement est indéfini.
POSIX dit (renvoie aussi explicitement au standard C):
Si stream pointe vers un flux de sortie ou un flux de mise à jour dans lequel l’opération la plus récente n’était pas en entrée, fflush() doit provoquer l’écriture dans le fichier de toute donnée non écrite pour ce flux, …
Mais la page de manuel de Linux dit:
Pour les flux de sortie, fflush() force une écriture de toutes les données tamponnées de l’espace utilisateur pour le flux de sortie ou de mise à jour donné via la fonction d’écriture sous-jacente du flux. Pour les flux d’entrée, fflush() jette toutes les données mises en tampon qui ont été récupérées depuis le fichier sous-jacent, mais qui n’ont pas été consommées par l’application. L’état ouvert du flux n’est pas affecté.