web-dev-qa-db-fra.com

Que fait fflush (stdin) dans la programmation C?

Je suis très nouveau dans la programmation C et j'essaie de comprendre comment fflush(stdin) fonctionne vraiment.

Dans l'exemple suivant, fflush(stdin) efface-t-il tout le tampon ou efface-t-il tout ce qui est entré après le troisième élément? Ce que je veux dire, c'est que l'utilisateur entre le numéro de compte, l'espace, le nom, l'espace, le solde. Est-il vrai qu'à partir de ce moment, tout ce que l'utilisateur saisit sera vidé avec fflush(stdin)? et stdin ne sera pas vide.

Pourquoi est-ce que je dis cela parce qu'il entre dans une boucle while et commence à écrire dans le fichier texte.

Ma deuxième question est de savoir si Ctrl-Z dira au système d'exploitation de ne plus demander à l'utilisateur d'entrer une entrée?

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 );
19
C graphics

La réponse à cette question est que fflush(stream) n'est défini formellement 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 vider le système d'exploitation tous les tampons dans le fichier sous-jacent. Pour un exemple d'utilisation légitime, les élèves ont souvent des problèmes comme "mon invite n'apparaît pas!" S'ils font quelque chose comme:

printf("Enter a number: ");

Cependant, 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, ils ont donc un petit problème.

La raison en est que la sortie vers stdout est mise en mémoire tampon par le système d'exploitation et le comportement par défaut est (souvent) de n'écrire la sortie sur le terminal qu'en cas de retour à la ligne. L'ajout d'une fflush(stdout) après la 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 éliminer toute entrée inutilisée, mais si vous y réfléchissez un peu, cela n'a pas beaucoup de sens. Que signifie "vider" un tampon d'entrée? Où est-il "vidé" à? Si vous videz un tampon de sortie, la sortie est envoyée au fichier sous-jacent ou au terminal, où elle finirait de toute façon, mais où entrée "finirait de toute façon"? Il n'y a aucun moyen de savoir! Quel devrait être le comportement si les données du flux d'entrée proviennent d'un fichier ou d'un canal ou d'une 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 l'ont fait implémentent un schéma où il fonctionnait comme beaucoup de gens s'y attendaient, en éliminant les inutilisés contribution. Microsoft DOS 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 une entrée de terminal indésirable "supplémentaire" est simplement de la lire et de ne rien en faire. C'est presque aussi simple que d'appeler fflush(stdin), fonctionne partout et ne repose pas sur un comportement formellement indéfini.

La norme [~ # ~] c [~ # ~] dit:

Si le flux pointe vers un flux de sortie ou un flux de mise à jour dans lequel l'opération la plus récente n'a pas été entrée, la fonction fflush entraîne la transmission de toutes les données non écrites pour ce flux être livré à l'environnement hôte pour être écrit dans le fichier; sinon, le comportement n'est pas défini .

POSIX dit (renvoie également explicitement à [~ # ~] c [~ # ~] standard):

Si le flux pointe vers un flux de sortie ou un flux de mise à jour dans lequel l'opération la plus récente n'a pas été entrée, fflush () doit provoquer des données non écrites pour ce flux à écrire dans le dossier, ...

Mais la page de manuel Linux dit:

Pour les flux de sortie, fflush () force l'é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 () supprime toutes les données mises en mémoire tampon qui ont été extraites du fichier sous-jacent, mais qui n'ont pas été consommées par l'application . Le statut ouvert du flux n'est pas affecté.

32
Emmet

fflush(stdin) invoque un comportement non défini.

fflush() est défini uniquement pour les flux de sortie. Tu ne devrais pas le faire.


Sous Unix, Ctrl-Z envoie un signal TSTP (SIGTSTP) qui, par défaut, suspend l'exécution du processus.

16
chrk