IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

 C Discussion :

fflush(stdin) et viderBuffer


Sujet :

C

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Homme Profil pro
    etudiants en programation
    Inscrit en
    Janvier 2017
    Messages
    22
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 29
    Localisation : Cameroun

    Informations professionnelles :
    Activité : etudiants en programation

    Informations forums :
    Inscription : Janvier 2017
    Messages : 22
    Par défaut fflush(stdin) et viderBuffer
    bonjour/ bonsoir s'il vous plait je voudrai savoir la différence en ces deux fonctions:

    et


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    void viderBuffer()
    {
        int c = 0;
        while (c != '\n' && c != EOF)
        {
            c = getchar();
        }
    }
    Bizarrement les deux servent à vider le buffer je voulais savoir la plus efficace et pourquoi?
    Merci.

  2. #2
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Chercheur d'emploi
    Inscrit en
    Septembre 2007
    Messages
    7 474
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Chercheur d'emploi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 474
    Par défaut
    Bonjour,

    Le comportement de fflush(stdin) est indéfini. Tu ne peux donc PAS affirmer que cela va bien vider ton buffer d'entrée.

    « flush » sert à vider un buffer de sortie, mais doit s'entendre dans le sens de « tirer la chasse ». C'est-à-dire qu'il ne détruit pas le contenu du buffer mais, au contraire, provoque son envoi immédiat vers son destinataire (généralement l'écran dans le cas de stdout), là ou justement, on met par défaut les données en attente le temps d'en avoir suffisamment ou de laisser une condition particulière se produire (retour à la ligne, timeout, fin du processus, etc.).

    Dans le cas de stdin, le destinataire, c'est justement le processus qui est à l'origine de l'appel : « fflush(stdin) » signifierait donc « envoie-moi immédiatement tout ce qui m'est destiné », et ce contenu a toujours été à disposition du processus. Le comportement le plus cohérent consiste donc, dans ce cas, à ne rien faire du tout, mais comme la norme C refuse (à juste titre) de définir tout comportement réglementaire à tenir, certains systèmes profitent de ce libre champ pour effacer le buffer quand même et présenter cela comme une fonctionnalité disponible, ce qui fait prendre de mauvaises habitudes au programmeur.

    C'est intéressant parce que cela montre que tu ne peux pas non plus détruire le contenu d'un buffer de sortie de cette façon : fflush(stdout) enverra bien le contenu vers son destinataire, mais tu ne pourra pas l'annuler.

    L'ennui, à ce stade, est que provoquer l'abandon des données déjà reçues ne relève pas du langage C standard : c'est de la programmation système (dépendante de ton OS), voire matérielle. Certes, la bibliothèque C standard tient des buffers pour ses propres opérations, mais rien ne te permet de savoir a priori qu'une frappe clavier, par exemple, se trouve déjà dans le buffer de stdin si le processus a du retard.


    Voir aussi cette discussion :
    https://www.developpez.net/forums/d1...nction-fflush/

  3. #3
    Membre actif
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2013
    Messages
    54
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mars 2013
    Messages : 54
    Par défaut
    Salut,

    personnellement, j'utilise une macro..
    C'est beaucoup plus facile a utiliser ou tu veux dans ton code sans l'alourdir..

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    #define CLEAR_STDIN { int c; while((c = getchar()) != '\n' && c != EOF); }

  4. #4
    Expert éminent

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 202
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 202
    Par défaut
    Quel gain par rapport à une fonction?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    void clear_stdin() { for(int c = 0; c!='\n' && c!=EOF; c = getchar()); }
    Une macro est un excellent moyen de faire provoquer des problèmes.
    En l'occurence, ta macro est un identifieur, pas une macro appelée, et elle n'aime pas avoir un point virgule qui la suit.
    Du coup, tu as un nom sans parenthèses, ni point virgules, qui n'est pas une valeur, et fait quelque chose.

    Ca casse l'esthétique du code, et donc sa lisibilité.

  5. #5
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 830
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 830
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Dunkhan Voir le message
    personnellement, j'utilise une macro..
    Bonjour

    Personnellement je contrôle toujours mon stdin donc si je provoque une saisie c'est que je sais qu'il est vide donc je n'ai pas besoin de le vider (c'est d'ailleurs parce qu'on n'a théoriquement jamais besoin de le vider que fflush(stdin) reste indéterminé). Si stdin a des trucs dedans c'est déjà d'une part parce que quelqu'un (ou quelque chose) les y a mis et donc d'autre part c'est pour que ces trucs soient traités.
    Et donc vider stdin c'est aussi ne plus pouvoir utiliser ton programme dans cette configuration: commande_externe | ton_programme. Hé oui, stdin ne signifie pas forcément "clavier" (ou du moins pas tout le temps)...

    Citation Envoyé par Dunkhan Voir le message
    C'est beaucoup plus facile a utiliser ou tu veux dans ton code sans l'alourdir...
    Idem²
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  6. #6
    Membre averti
    Homme Profil pro
    etudiants en programation
    Inscrit en
    Janvier 2017
    Messages
    22
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 29
    Localisation : Cameroun

    Informations professionnelles :
    Activité : etudiants en programation

    Informations forums :
    Inscription : Janvier 2017
    Messages : 22
    Par défaut
    Citation Envoyé par Sve@r Voir le message
    Bonjour

    Personnellement je contrôle toujours mon stdin donc si je provoque une saisie c'est que je sais qu'il est vide donc je n'ai pas besoin de le vider (c'est d'ailleurs parce qu'on n'a théoriquement jamais besoin de le vider que fflush(stdin) reste indéterminé). Si stdin a des trucs dedans c'est déjà d'une part parce que quelqu'un (ou quelque chose) les y a mis et donc d'autre part c'est pour que ces trucs soient traités.
    Et donc vider stdin c'est aussi ne plus pouvoir utiliser ton programme dans cette configuration: commande_externe | ton_programme. Hé oui, stdin ne signifie pas forcément "clavier" (ou du moins pas tout le temps)...


    Idem²
    hummm excuse moi mais je ne te comprends pas ce que je voudrais savoir pourquoi dois-je utiliser cette fonction au lieu de fflush(stdin) ou porquoi dois-je utiliser fflush(stdin) au lieu de cette fonction
    merci

  7. #7
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 830
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 830
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par a.brice Voir le message
    soit plus explicite quand tu dis <<indéfini>> au départ merci
    Prends-le exactement dans sa forme littérale la plus pure: un comportement indéfini (perso je dis plutôt "indéterminé") est un comportement qu'on ne connait pas donc qu'on ne peut pas définir.

    Citation Envoyé par a.brice Voir le message
    ce que je voudrais savoir pourquoi dois-je utiliser cette fonction au lieu de fflush(stdin)
    Parce que l'instruction fflush(stdin) est une instruction illicite et donc le C ne te garantit absolument pas le comportement de cette instruction. Ca peut vider stdin, ne pas le vider mais ne rien faire d'autre, inverser ton écran, rebooter ton PC, reformater ton disque dur, etc.
    Ca peut marcher, ne pas marcher, marcher les jours pairs et ne pas marcher les jours impairs, etc etc etc. C'est exactement ce que ça signifie chaque fois que tu verras en C le terme "comportement indéterminé".

    Il faut savoir que le C est totalement permissif. Pour aller le plus vite possible il ne vérifie absolument pas si ce que tu écris est autorisé. Si ça l'est tout va bien, si ça ne l'est pas tu tombes alors dans le "comportement indéterminé". C'est donc à toi de savoir en permanence ce que tu écris et pourquoi tu l'écris.

    Alors que le code de cette fonction, lui, est parfaitement licite et fait exactement ce qui est écrit.

    Citation Envoyé par a.brice Voir le message
    ou pourquoi dois-je utiliser fflush(stdin) au lieu de cette fonction
    Ce que je dis, moi, c'est que tu ne dois utiliser ni l'un ni l'autre mais au contraire toujours maîtriser ton stdin pour ne jamais avoir besoin de le vider ni même imaginer avoir besoin de le vider. Si tu maitrises en permanence les données qui y entrent et que tu traites ces données dans leur intégralité ben en effet il n'y a aucune raison d'avoir besoin de le vider.
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  8. #8
    Membre averti
    Homme Profil pro
    etudiants en programation
    Inscrit en
    Janvier 2017
    Messages
    22
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 29
    Localisation : Cameroun

    Informations professionnelles :
    Activité : etudiants en programation

    Informations forums :
    Inscription : Janvier 2017
    Messages : 22
    Par défaut
    Citation Envoyé par Obsidian Voir le message
    Bonjour,

    Le comportement de fflush(stdin) est indéfini. Tu ne peux donc PAS affirmer que cela va bien vider ton buffer d'entrée.

    « flush » sert à vider un buffer de sortie, mais doit s'entendre dans le sens de « tirer la chasse ». C'est-à-dire qu'il ne détruit pas le contenu du buffer mais, au contraire, provoque son envoi immédiat vers son destinataire (généralement l'écran dans le cas de stdout), là ou justement, on met par défaut les données en attente le temps d'en avoir suffisamment ou de laisser une condition particulière se produire (retour à la ligne, timeout, fin du processus, etc.).
    soit plus explicite quand tu dis <<indéfini>> au départ merci

  9. #9
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Chercheur d'emploi
    Inscrit en
    Septembre 2007
    Messages
    7 474
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Chercheur d'emploi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 474
    Par défaut
    Bonjour,

    Citation Envoyé par a.brice Voir le message
    soit plus explicite quand tu dis <<indéfini>> au départ merci
    Cela signifie que la norme C elle-même indique que le comportement de fflush() sur un flux d'entrée est officiellement indéfini, c'est-à-dire qu'elle refuse de statuer sur ce point :

    Citation Envoyé par n1256
    2 If stream points to an output stream or an update stream in which the most recent
    operation was not input
    , the fflush function causes any unwritten data for that stream
    to be delivered to the host environment to be written to the file; otherwise, the behavior is
    undefined
    .

    Donc, déjà, sur ce point en particulier : on sait à présent que fflush(stdin) n'a jamais existé en soi, et que c'est directement la norme qui te dit si tu le fais quand même, personne ne pourra te garantir le résultat.

    Outre ce cas de figure, il est très fréquent de rencontrer des « comportements indéfinis » (undefined behavour) dans la norme C. Cela ne veut pas dire que la norme est incomplète, ni que ses rédacteurs se sont mis dans une impasse. C'est en fait une attitude à avoir et que l'on retrouve fréquemment, entre autre, en électronique numérique : chaque contrainte a des effets de bord sur l'implémentation et il est parfois compliqué de toutes les honorer à la fois. Donc il vaut mieux laisser « en l'air » tout ce qui sort de l'objectif ciblé plutôt que d'imposer arbitrairement des valeurs ou comportements par défaut qui seront compliqués à mettre en œuvre et qui ne serviront à rien.

    Par exemple : le plus petit type natif de donnée en langage C est le char, dont le sizeof() vaut toujours 1 par définition. La plupart du temps, 1 char = 1 octet, ce qui est généralement le format choisi par le reste de l'industrie, même en dehors du langage C. Pourtant, le langage C le définit, lui, comme un entier binaire suffisamment long pour pouvoir représenter les 91 caractères réglementaires réclamés par la même norme, soit en théorie, un minimum de 7 bits. Ceci permet de faire passer des char à travers une transmission série à parité (Ex : 7 bits, parité paire, un bit de stop, comme sur le Minitel) mais aussi d'implémenter cela facilement sur les architectures qui ne se basent pas sur l'octet : certains micro-contrôleurs, par exemple, utilisent des mots de 12 bits pour les instructions programme et 8 bits pour la RAM intégrée. Dans cet exemple, il est tout-à-fait légal de coder un char sur 12 bits de façon à ce que 1 mot binaire corresponde à 1 caractère. Si la norme avait spécifié « 1 char = 1 octet » parce que c'est ce qui aurait semblé le plus naturel sur le coup, il aurait été beaucoup plus compliqué d'implémenter un compilateur.


    Par ailleurs, en ce qui concerne fflush(stdin) en particulier, il faut bien se rendre compte que tout part d'une mauvaise perception (fréquente) de ce à quoi sert fflush() en soi : si cela vide bien un buffer, c'est APRÈS en avoir traité le contenu et s'être assuré de son intégrité. C'est tout le contraire d'un abandon.


    Enfin, pour être exact, on s'aperçoit que le fflush() des man pages de Linux présente un comportement similaire MAIS :

    Citation Envoyé par man fflush
    CONFORMING TO
    C89, C99, POSIX.1-2001, POSIX.1-2008.

    POSIX.1-2001 did not specify the behavior for flushing of input streams, but the behavior is specified in POSIX.1-2008.

    Ça veut dire que ce n'est pas dans C89, ce n'est pas dans C99, ce n'est MÊME PAS dans POSIX-2001, mais que POSIX-2008 a fini par statuer tellement les gens faisaient l'erreur souvent. Et quand on cherche ladite déclaration, on tombe sur ça : http://pubs.opengroup.org/onlinepubs/9699919799/

    Citation Envoyé par POSIX.1-2008
    The Open Group Base Specifications Issue 7
    IEEE Std 1003.1-2008, 2016 Edition
    Copyright © 2001-2016 The IEEE and The Open Group

    The functionality described on this reference page is aligned with the ISO C standard. Any conflict between the requirements described here and the ISO C standard is unintentional. This volume of POSIX.1-2008 defers to the ISO C standard.

    C'est en tête de page et en surbrillance : POSIX-2008, au moins sur ce point, s'aligne sur le C ISO. En 2008, c'était C99, vu au dessus. Aujourd'hui, c'est C11. Et quand on cherche le dernier draft de C11, on lit la même chose :

    Citation Envoyé par n1570
    2 If stream points to an output stream or an update stream in which the most recent
    operation was not input, the fflush function causes any unwritten data for that stream
    to be delivered to the host environment to be written to the file; otherwise, the behavior is
    undefined.

    Donc rien de nouveau sous le soleil dans la dernière version de la norme C. Comme ce comportement est « indéfini », POSIX-2008 propose quand même ceci :

    For a stream open for reading with an underlying file description, if the file is not already at EOF, and the file is one capable of seeking, the file offset of the underlying open file description shall be set to the file position of the stream, and any characters pushed back onto the stream by ungetc() or ungetwc() that have not subsequently been read from the stream shall be discarded (without further changing the file offset).

    Ça veut dire que — si c'est possible — un fflush(stdin) doit adopter le même comportement qu'un fflush(stdout), c'est-à-dire vider le buffer en retournant les caractères vers leur expéditeur plutôt qu'en les envoyant vers leur destinataires, mais en aucun cas les détruire. Cela signifie aussi que vu de ton programme, cela n'aurait aucun effet visible : les caractères seraient d'abord renvoyés au périphérique en amont, puis rappelés à la ligne d'après, ce qui remplirait à nouveau le buffer. Et tu récupérerais alors les mêmes caractères, alors même que tu as voulu t'en débarrasser.

    Si l'on veut utiliser cette possibilité, il faut aussi garantir que le programme est bien écrit en contexte POSIX-2008, avec les bonnes features macros en tête de programme, et avec une ligne de commentaire au dessus de l'appel pour justifier son utilisation.



    En bref : aucune raison d'utiliser fflush(stdin), ni sur la forme, ni sur le fond.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 1
    Dernier message: 25/02/2009, 18h23
  2. [Débutant] Différence entre fonction et procédure
    Par secondechance dans le forum Langage
    Réponses: 9
    Dernier message: 21/08/2008, 21h11
  3. Réponses: 0
    Dernier message: 14/03/2008, 00h16
  4. API Windows différence entre fonctions simple EX et A
    Par Astraya dans le forum Windows
    Réponses: 3
    Dernier message: 11/02/2008, 09h39
  5. différence entre fonction() et fonction(void)
    Par ram-0000 dans le forum C++
    Réponses: 8
    Dernier message: 07/11/2007, 17h31

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo