OVH Cloud OVH Cloud

Vider le buffer associe a stdin

98 réponses
Avatar
korchkidu
Bonjour,

je me pose une question par rapport a la maniere classique de vider le
buffer associe a stdin:

c = getchar();
if (c != ’\n’)
while ( (getchar()) != ’\n’) {
};

Que se passe t-il si stdin ne contient aucun \n? (fichier contenant une
ligne mais aucun \n par exemple). Dans ce cas, il me semble que l'on
pourrait avoir un probleme non?

Comment feriez vous pour resoudre ce probleme? (J'ai bien une petite
idee mais je prefere savoir si c'est la bonne..;) )

Merci d'avance pour vos reponses,
K.

10 réponses

1 2 3 4 5
Avatar
Charlie Gordon
"korchkidu" wrote in message
news:4182295a$
Marc Boyer wrote:
korchkidu wrote:

Bonjour,

je me pose une question par rapport a la maniere classique de vider le
buffer associe a stdin:

c = getchar();
if (c != ’n’)
while ( (getchar()) != ’n’) {
};



C'est la manière classique ?


C'est celle qui est detaillee dans la FAQ. C'est effectivement ce que
j'entendais par classique..;)

http://www.isty-info.uvsq.fr/~rumeau/fclc/fclc0014.html#q_4

A moins que celle-ci ne soit pas la bonne....


Il faudrait reviser la FAQ : telle que présentée, cette méthode peut conduire à
une boucle infinie, même avec un clavier : il suffit en effet d'y entrer une fin
de fichier, ce qui est trivial sous unix, et même sous CMD.EXE

De plus, le ; final est d'une utilité douteuse : utilise plutot des {} pour le
if aussi.

Enfin la valeur du caractère lu n'est pas disponible dans la boucle (si on
cherchait à y tester EOF pas exemple).

Je propose :

{
int c;
while ((c = getchar()) != EOF) {
if (c == 'n')
break;
}
}

Mais if faut bien souligner que cette façon d'ignorer les données soumises à un
programme est très suspecte.

Chqrlie.



Avatar
Charlie Gordon
void skeep_line(FILE* in){
int c;
do {
c= getchar(in);
} while( c != 'n' && c != EOF);
}

Non ?


NON :
- skeep -> skip
- getc(in) et non getchar(in)
- éviter d'utiliser in comme nom de variable, c'est un mot clé dans nombre de
dialectes dérivés.
- éviter les boucles do/while qui sont souvent beuguées.

Je préfère qu'on utilise l'idiome >> while ((c = getc(in)) != EOF) << et tester
le condition spécifique sur 'n' dans le corps de la boucle. C'est moins bô,
mais moins souvent beugué par les modifications ultérieures.

Chqrlie.

Avatar
Laurent Deniau
Charlie Gordon wrote:
void skeep_line(FILE* in){
int c;
do {
c= getchar(in);
} while( c != 'n' && c != EOF);
}

Non ?



NON :
- skeep -> skip
- getc(in) et non getchar(in)
- éviter d'utiliser in comme nom de variable, c'est un mot clé dans nombre de
dialectes dérivés.


Cela n'a pas d'importance tant que la fonction n'est pas inline dans un
header, ce qui est le cas ici.

- éviter les boucles do/while qui sont souvent beuguées.


Veux-tu dire que les compilos traduisent mal les do/while? As-tu des
exemples concrets (compilo, code C, code asm) pour dire que do/while est
moins fiable de while? (je dois dire que je suis sceptique).

Je préfère qu'on utilise l'idiome >> while ((c = getc(in)) != EOF) << et tester
le condition spécifique sur 'n' dans le corps de la boucle.


C'est aussi ma preference mais pour des raisons de lisibilite, pas a
cause de pretendu bug des compilateurs.

Ceci dit le C permet d'ecrire du code compact (a-la-perl) et les
debutants ont tendance a penser que plus le code est compact, plus il
s'execute rapidement alors qu'il n'y a en principe pas de cause a effet
du moment que la semantique est la meme...

a+, ld.


Avatar
Charlie Gordon
"Laurent Deniau" wrote in message
news:cm82vi$c50$
Charlie Gordon wrote:
void skeep_line(FILE* in){
int c;
do {
c= getchar(in);
} while( c != 'n' && c != EOF);
}

Non ?


NON :
- skeep -> skip
- getc(in) et non getchar(in)
- éviter d'utiliser in comme nom de variable, c'est un mot clé dans nombre
de


dialectes dérivés.


Cela n'a pas d'importance tant que la fonction n'est pas inline dans un
header, ce qui est le cas ici.


C'est une mauvaise habitude. Il est préférable de s'abstenir utiliser les mots
clés du C++ dans du code C aussi : class, private, public, this, new, delete...
Cela ne cause pas de beugues tout de suite, mais rend le code moins portable, et
surtout moins lisible.

- éviter les boucles do/while qui sont souvent beuguées.


Veux-tu dire que les compilos traduisent mal les do/while? As-tu des
exemples concrets (compilo, code C, code asm) pour dire que do/while est
moins fiable de while? (je dois dire que je suis sceptique).


Pas du tout, je ne mets pas en cause les compilateurs C, mais les programmeurs.
La boucle do/while est parfaitement définie dans le langage, et semble utile
pour certains cas de boucles ou la première itération doit toujours être faite.
J'ai malheureusement souvent constaté que la façon de construire ces boucles
conduit de nombreux programmeurs à y introduire des beugues que l'utilisation
d'un for() aurait évités. Donc je recommande d'éviter d'utiliser do/while, et
de se méfier de ceux qu'on rencontre.

Personnellement, je n'utilise do/while que dans certaines macros, pour encadrer
des blocs d'instructions au sein d'une instruction unique:

#define some_macro(a,b) do { foo(a); bar(b); } while(0)

Ou pour implementer des constructions spéciales comme tu le fais dans tes
packages oopc et exception.

Chqrlie.



Avatar
Laurent Deniau
Charlie Gordon wrote:
"Laurent Deniau" wrote in message
news:cm82vi$c50$

Charlie Gordon wrote:

void skeep_line(FILE* in){
int c;
do {
c= getchar(in);
} while( c != 'n' && c != EOF);
}

Non ?


NON :
- skeep -> skip
- getc(in) et non getchar(in)
- éviter d'utiliser in comme nom de variable, c'est un mot clé dans nombre



de

dialectes dérivés.


Cela n'a pas d'importance tant que la fonction n'est pas inline dans un
header, ce qui est le cas ici.



C'est une mauvaise habitude. Il est préférable de s'abstenir utiliser les mots
clés du C++ dans du code C aussi : class, private, public, this, new, delete...
Cela ne cause pas de beugues tout de suite, mais rend le code moins portable, et
surtout moins lisible.


Il faut aussi dans ce cas eviter id (tres utilise), self et d'autres
pour Objective-C. Je pense que dans le cadre de fonctions inline ou de
macros dans les headers, je suis d'accord qu'il faut faire tres
attention aux identifiers que l'on utilise et plus generalement au code
que l'on ecrit. Mais dans le corps du code C, il y a deja assez a faire
avec l'ecriture d'un code correct.

- éviter les boucles do/while qui sont souvent beuguées.


Veux-tu dire que les compilos traduisent mal les do/while? As-tu des
exemples concrets (compilo, code C, code asm) pour dire que do/while est
moins fiable de while? (je dois dire que je suis sceptique).



Pas du tout, je ne mets pas en cause les compilateurs C, mais les programmeurs.


D'accord.

La boucle do/while est parfaitement définie dans le langage, et semble utile
pour certains cas de boucles ou la première itération doit toujours être faite.
J'ai malheureusement souvent constaté que la façon de construire ces boucles
conduit de nombreux programmeurs à y introduire des beugues que l'utilisation
d'un for() aurait évités. Donc je recommande d'éviter d'utiliser do/while, et
de se méfier de ceux qu'on rencontre.

Personnellement, je n'utilise do/while que dans certaines macros, pour encadrer
des blocs d'instructions au sein d'une instruction unique:

#define some_macro(a,b) do { foo(a); bar(b); } while(0)


Il m'arrive de faire aussi cela avec un while. Par exemple

#define checkSysError while(errno) throw(new(eSysErr))

(en fait cette macro est un peu plus compliquee parce que l'exception
eSysErr sauve et clear errno alors que sa creation peut elle-meme
changer la valeur de errno. Il y a donc 3 etapes au lieu d'une).

Ou pour implementer des constructions spéciales comme tu le fais dans tes
packages oopc et exception.


Tiens ca me fait penser que je devrais mettre OOC-2.0 sur le web des que
j'ai du temps. Cette version devrait tout de meme etre plus utile que
les deux packages que tu cites.

a+, ld.




Avatar
Emmanuel Delahaye
Charlie Gordon wrote on 03/11/04 :
C'est une mauvaise habitude. Il est préférable de s'abstenir utiliser les
mots clés du C++ dans du code C aussi : class, private, public, this, new,
delete...


Au contraire. C'est un bon moyen d'éviter que du code C se retrouve par
erreur compilé en C++, ce qui n'est un giganteste UB.

Cela ne cause pas de beugues tout de suite, mais rend le code moins portable,
et surtout moins lisible.


Portable avec quoi ?

Pas du tout, je ne mets pas en cause les compilateurs C, mais les
programmeurs. La boucle do/while est parfaitement définie dans le langage, et
semble utile pour certains cas de boucles ou la première itération doit
toujours être faite. J'ai malheureusement souvent constaté que la façon de
construire ces boucles conduit de nombreux programmeurs à y introduire des
beugues que l'utilisation d'un for() aurait évités. Donc je recommande
d'éviter d'utiliser do/while, et de se méfier de ceux qu'on rencontre.


C'est le programmeur qui est beugué, pas la boucle... do-while a son
role (le repeat until du Pascal à une vache près). Il n'y a aucune
raison de ne pas l'utiliser quand c'est utile. Tu as de drôles de
préjugés parfois...

Personnellement, je n'utilise do/while que dans certaines macros, pour
encadrer des blocs d'instructions au sein d'une instruction unique:

#define some_macro(a,b) do { foo(a); bar(b); } while(0)


Ben c'est dommage de se limiter à ça. Comment tu codes


. |<----------
. | |
. --------------- |
. | faire un truc | |
. --------------- |
. | |
. ---------- N |
. < OK ? >----
. ----------
. | O
. |

--
Emmanuel
The C-FAQ: http://www.eskimo.com/~scs/C-faq/faq.html
The C-library: http://www.dinkumware.com/refxc.html

"C is a sharp tool"

Avatar
Charlie Gordon
"Emmanuel Delahaye" wrote in message
news:
Charlie Gordon wrote on 03/11/04 :
C'est une mauvaise habitude. Il est préférable de s'abstenir utiliser les
mots clés du C++ dans du code C aussi : class, private, public, this, new,
delete...


Au contraire. C'est un bon moyen d'éviter que du code C se retrouve par
erreur compilé en C++, ce qui n'est un giganteste UB.


Ton argument est completement tiré par les cheveux. En l'occurrence, compiler
en C++ est souvent un bon moyen de découvrir des problèmes.

Cela ne cause pas de beugues tout de suite, mais rend le code moins
portable,


et surtout moins lisible.


Portable avec quoi ?


Avec C++ justement! Si d'aventure tu devais porter des routines C dans une
appli C++, tu serais bien content de ne pas avoir à aller à la pêche aux
mots-clés.

Mais l'argument principal pour moi est la lisibilité : si le lecteur connait et
pratique le C et le C++, voire d'autres dialectes dérivés, l'utilisation de
mots-clés pour un autre usage ralentit la lecture, voire engendre de mauvaises
interprétations. C est un langage déjà suffisament subtil pour ne pas rajouter
de pièges au lecteur futur.

Pas du tout, je ne mets pas en cause les compilateurs C, mais les
programmeurs. La boucle do/while est parfaitement définie dans le langage,
et


semble utile pour certains cas de boucles ou la première itération doit
toujours être faite. J'ai malheureusement souvent constaté que la façon de
construire ces boucles conduit de nombreux programmeurs à y introduire des
beugues que l'utilisation d'un for() aurait évités. Donc je recommande
d'éviter d'utiliser do/while, et de se méfier de ceux qu'on rencontre.


C'est le programmeur qui est beugué, pas la boucle... do-while a son
role (le repeat until du Pascal à une vache près). Il n'y a aucune
raison de ne pas l'utiliser quand c'est utile. Tu as de drôles de
préjugés parfois...


Je cite un exemple de la faq de developpez.com où tu sévis régulièrement (mais
dont tu n'es pas l'auteur) :

Comment gérer les touches étendues (F1..F12, flèches) ?

#include <conio.h>

int main(void)
{ int touche ;

do
{
if(kbhit()) // Si présence d'une touche...
{
touche = getch() ; // ... la lire
if(!touche) // Si touche double code...
{
touche = getch() ; // ... la lire
switch(touche) // ... et effectuer le traîtement
{
case FLG: // Flêche Gauche (0x4B)
// Traîtement
break ;
case FLD: // Flêche Droite (0x4D)
// Traîtement
break ;
case FLH: // Flêche Haute (0x48)
// Traîtement
break ;
case FLB: // Flêche Basse (0x50)
// Traîtement
break ;
} ;
}
else // Si touche unicode (standard)
{
switch(touche)
{
case '1' :
// Traîtement
break ;
case '2' :
// Traîtement
break ;
case '3' :
// Traîtement
break ;
} ;
}
}

// Ici votre programme

}
while(touche!=ESC) ; // Tant que touche différent de ESC (0x1B)
return 0 ;
}

Voilà un exemple parfait de mon propos :

Tu remarqueras que '// Ici votre programme' sera exécuté aussi dans le cas de
la touche ESC, ce qui n'est à l'évidence pas l'intention de l'auteur !

Mais il y a pire encore : ce programme utilise potentiellement (et pratiquement
à coup sûr) la variable 'touche' avant qu'elle soit initialisée ! Il risque
fort de sortir directement de façon imprévisible et non-reproductible.

C'est un exemple typique de construction de programme où l'utilisation de la
boucle do/while conduit à un comportement incorrect. Dans cet exemple, il
serait bien préférable d'utiliser le code suivant :

int touche;
for (;;) {
touche = -1; /* pas de touche */
if (kbhit()) { /* Si présence d'une touche... */
touche = getch() ; /* ... la lire */
if (!touche) { /* Si touche double code... */
... /* le code ici ne devrait pas laisser dans touche une valeur
ambiguë */
} else {
if (c == ESC) /* test de sortie */
break;
...
}
}
/* Ici votre programme... */
}

Tous les programmeurs sont beugués : il m'a fallu longtemps pour l'admettre et
j'en ai rencontré de tous niveaux dont quelques rares mais authentiques génies.
Mais les génies ne sont pas des surhommes : s'ils font moins d'erreurs que les
autres, c'est aussi parce qu'ils ont appris à se méfier et évitent de prendre
des risques stupides.

Chqrlie.


Avatar
Jean-Marc Bourguet
"Charlie Gordon" writes:

Tous les programmeurs sont beugués : il m'a fallu longtemps pour
l'admettre et j'en ai rencontré de tous niveaux dont quelques rares
mais authentiques génies. Mais les génies ne sont pas des surhommes
: s'ils font moins d'erreurs que les autres, c'est aussi parce
qu'ils ont appris à se méfier et évitent de prendre des risques
stupides.




A+

--
Jean-Marc
FAQ de fclc: http://www.isty-info.uvsq.fr/~rumeau/fclc
Site de usenet-fr: http://www.usenet-fr.news.eu.org

Avatar
Laurent Deniau
Charlie Gordon wrote:
"Emmanuel Delahaye" wrote in message
news:

Charlie Gordon wrote on 03/11/04 :

C'est une mauvaise habitude. Il est préférable de s'abstenir utiliser les
mots clés du C++ dans du code C aussi : class, private, public, this, new,
delete...


Au contraire. C'est un bon moyen d'éviter que du code C se retrouve par
erreur compilé en C++, ce qui n'est un giganteste UB.



Ton argument est completement tiré par les cheveux. En l'occurrence, compiler
en C++ est souvent un bon moyen de découvrir des problèmes.


Alors je crois que tu t'avances un peu. Avant de jouer a l'apprenti
sorcier avec un compilateur C++, tu devrais relire les sections "C++
compatibility" du Harbison-Steele (a chaque fin de chapitre) et
l'appendix B du TC++PL3, notament les "silent differences". L'edition
speciale de ce dernier (couverture blanche) est je crois plus complete
sur ce sujet mais je ne l'ai pas sous la main pour verifier (il est chez
moi).

Cela ne cause pas de beugues tout de suite, mais rend le code moins



portable,

et surtout moins lisible.


Portable avec quoi ?



Avec C++ justement! Si d'aventure tu devais porter des routines C dans une
appli C++, tu serais bien content de ne pas avoir à aller à la pêche aux
mots-clés.


De toute facon il faudra passer attentivement a travers le code vu que
le copier-coller sans verification est exclut. C et C++ sont tres
different, rendre ses headers compatible est deja un bon depart.

D'autre part il est tres rare que du code C ne soit pas completement
repense quand il passe en C++. Il n'y a rien de pire que du C importe
directement dans un projet C++ et laisse en l'etat (aux erreurs/warnings
de compilation pret). Donc a moins que tu ais tu temps a perdre sur un
hypotetique futur portage, je dirais qu'il y a d'autres points plus
important sur lesquels il faut se concentrer comme tu le soulignes.

Mais l'argument principal pour moi est la lisibilité : si le lecteur connait et
pratique le C et le C++, voire d'autres dialectes dérivés, l'utilisation de
mots-clés pour un autre usage ralentit la lecture, voire engendre de mauvaises
interprétations. C est un langage déjà suffisament subtil pour ne pas rajouter
de pièges au lecteur futur.


C'est un point de vue.

a+, ld.



Avatar
Jean-Marc Bourguet
Laurent Deniau writes:

En l'occurrence, compiler en C++ est souvent un bon moyen de
découvrir des problèmes.


Alors je crois que tu t'avances un peu.


Nous venons de recompiler un gros programme (plusieurs dizaines de
millions de ligne de code) mixte fortran, c, c++ en compilant le c et
le c++ avec le compilateur c++. A ma connaissance, aucun probleme n'a
ete du a un changement de comportement silencieux entre c et c++.

Il a fallu changer des noms, utiliser const de maniere plus rigoureuse
(le C date parfois d'avant 89), etre plus rigoureux dans les pointeurs
sur fonction,... Mais aucun changement de comportements silencieux
(quelques problemes a cause de changements faits trop vite -- scripts
ne prevoyant pas certains cas principalement -- mais c'est autre
chose) et quelques problemes existants reveles.

A+

--
Jean-Marc
FAQ de fclc: http://www.isty-info.uvsq.fr/~rumeau/fclc
Site de usenet-fr: http://www.usenet-fr.news.eu.org


1 2 3 4 5