Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Problème avec EOF

12 réponses
Avatar
Francois
Bonjour à tous,

J'ai un léger souci avec ce code très simple du K&R2.

/* ---------------------------*/

#include <stdio.h>

main()
{
int nc ;
nc = 0 ;
while (getchar() != EOF)
++nc ;
printf("%d\n", nc) ;
}

/* ---------------------------*/

Il doit compter les caractères que je tape avec mon clavier et afficher
le résultat. Or, tant qu'il y a des éventuels caractères à lire en
entrée, le résultat ne s'affiche pas, même après avoir tapé ENTER, ce
qui est normal.

Si je mets "10" à la place "EOF", quand je tape ENTER, là le résultat
s'affiche, c'est bien normal aussi.

Voici ma question. Comme je me dit que le code devrait marcher tel quel,
je me demandais s'il n'y avait pas une touche du clavier qui serait
interprétée en entré comme "EOF" ?

Il me semble que globalement une touche du clavier correspond à un
caractère, mais peut-être pas toutes. Si je n'ai aucun moyen envoyer en
entrée un "EOF", je ne vois pas comment ce petit code peut fonctionner
tel quel.


Merci d'avance.



François

10 réponses

1 2
Avatar
Jean-Marc Bourguet
Francois writes:

Voici ma question. Comme je me dit que le code devrait marcher tel quel, je
me demandais s'il n'y avait pas une touche du clavier qui serait
interprétée en entré comme "EOF" ?


CTRL-D en debut de ligne sous Unix, je crois que CTRL-Z sous Windows a le
meme effet mais je ne suis pas sur.

Pour Unix, il y a une reponse beaucoup plus longue a faire mais qui n'a
rien a voir avec le C.

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
Xavier Roche
Voici ma question. Comme je me dit que le code devrait marcher tel quel,
je me demandais s'il n'y avait pas une touche du clavier qui serait
interprétée en entré comme "EOF" ?


"Control-D", en règle générale (terminaux type Unix)

Vous pouvez également le simuler avec:
printf "ma chaine ascii" | ./monprogramme

Il me semble que globalement une touche du clavier correspond à un
caractère, mais peut-être pas toutes.


"EOF" c'est en général "-1", donc cela ne correspond à aucune "touche"
ou caractère ascii. Ce n'est _pas_ un caractère, et il n'est pas non
plus présent dans les fichiers que vous lisez sur disque -- à proprement
parler c'est une donnée "hors bande". On pourrait de la même manière
définir arbitrairement des codes d'erreur distincts renvoyés par
getchar() (actuellement, une erreur provoque également "EOF")

Control-D (normalement mappé sur le code 4) est en fait "vu" par le
terminal (la console) et provoque la fermeture de l'entrée du programme
(stdin)

Dans le cas de:
printf "ma chaine ascii" | ./monprogramme

C'est la commande "printf" qui écrit "ma chaine ascii", puis se termine
normalement, fermant dans le même temps sa sortie stdout (redirigée vers
le stdin de "monprogramme"), provoquant l'apparition d'un EOF.

Avatar
Francois
Merci à tous les deux. C'est du rapide ! ;-)

Je ne connaissais pas Ctrl+D qui stoppe le flux d'entrée (stdin) si j'ai
bien compris. J'avais l'impression que le seul moyen pour moi était de
fermer mon terminal, auquel cas difficile de voir le résultat
s'afficher. :-)


Vous pouvez également le simuler avec:
printf "ma chaine ascii" | ./monprogramme


Parfait, ça aussi je ne connaissais pas.
Merci pour les explications. ;-)



François

Avatar
Xavier Roche
J'avais l'impression que le seul moyen pour moi était de
fermer mon terminal, auquel cas difficile de voir le résultat
s'afficher. :-)


Oui, car en plus de fermer stdin, cela provoque (sous Unix) également la
réception d'un signal "SIGHUP" (littéralement "le client a raccroché" ;
càd il a fermé sa connexion, du temps où tout se passait via des
terminaux connectés à des modem :p) qui par défaut fait exit()

Avatar
candide

Bonjour à tous,

J'ai un léger souci avec ce code très simple du K&R2.


Pour une meilleure lisibilité, merci d'indiquer des références précises,
en l'espèce § 1.5.2 du K&R.

Je viens de relire le contexte dont le programme est extrait : la
pédagogie du K&R est vraiment une abérration, je crois qu'on peut
difficilement faire pire.


#include <stdio.h>

main()


NON, dans la préface du K&R2 on lit :

"This Second Edition of The C Programming Language describes C as
defined by the ANSI standard. Although we have noted the places where
the language has evolved, we have chosen to write exclusively in the new
form."


et pourtant la norme ANSI indique :

"2.1.2.2 (...) It can be
defined with no parameters:
int main(void) { /*...*/ }
or (...)"

même si je sais bien que ce n'est pas une obligation.


Il doit compter les caractères que je tape avec mon clavier et afficher
le résultat. Or, tant qu'il y a des éventuels caractères à lire en
entrée, le résultat ne s'affiche pas, même après avoir tapé ENTER, ce
qui est normal.


Tu trouves ? quand tu fais un scanf, tu valides l'entrée avec ENTER donc
quoi de plus _naturel_ (je n'ai pas dit "exact") que de penser qu'il va
en être de même dans un programme qui joue sur les entrées. Une
documentation bien faite doit anticiper ce qu'un lecteur peut
_naturellement_ penser. Ce qui suppose que l'auteur ait une empathie
avec son lecteur. Assez rare.


Si je mets "10" à la place "EOF", quand je tape ENTER, là le résultat
s'affiche, c'est bien normal aussi.



Je comprends pas : si tu mets "10" dans quoi à la place "EOF" ? quand
même pas dans le fichier stdio.h. Ou alors tu mets "10" dans le fichier
ci-dessus à la place du symbole EOF ? et quel résultat s'affiche donc ?
Oui, OK j'ai compris mais tu n'es pas clair dans tes explications, en
plus "10" n'est pas portable, en plus chez moi, ça affiche des saletés
après avoir tapé ENTER.



Voici ma question. Comme je me dit que le code devrait marcher tel quel,
je me demandais s'il n'y avait pas une touche du clavier qui serait
interprétée en entré comme "EOF" ?


ce qui n'est pas évident à imaginer si on n'est pas au courant (comment
comprendre si on est pas initié que la fin de ce qu'on vient de taper
est la fin d'un ___fichier___ ?)



Il me semble que globalement une touche du clavier correspond à un
caractère, mais peut-être pas toutes. Si je n'ai aucun moyen envoyer en
entrée un "EOF", je ne vois pas comment ce petit code peut fonctionner
tel quel.



On t'a répondu. Tu aurais fait une recherche dans Google groups, tu
aurais vu que la question est fréquemment répondue. Je m'étais posée
moi-même la question sur ce forum :

http://groups.google.fr/group/fr.comp.lang.c/msg/adcfe02f170cb427 que

j'ai agrémenté de quelques recherches bibliographiques sur le sujet.


Jean-Marc Bourguet a sa batterie de test (entiers sur 32 bits, etc) moi
je suis en train de constituer la mienne. L'équivalent clavier du EOF et
toutes les explications relatives à la constante EOF font partie de mes
tests.

La FAQ de fclc ne passe pas ce test. D'un autre côté, cette faq répond à
un tas de questions rarement posées. Le C n'est pas un problème, c'est
sa doc qui en est un.

Avatar
Antoine Leca
En news:47d93098$0$2858$, candide va escriure:

#include <stdio.h>

main()


NON,


« Non » quoi ?


dans la préface du K&R2 on lit :

"This Second Edition of The C Programming Language describes C as
defined by the ANSI standard. Although we have noted the places where
the language has evolved, we have chosen to write exclusively in the
new form."


[ en n'oubliant pas de se replacer dans le contexte adéquat, ici BWK fait
référence à la norme de 1989/90 quand il parle de « nouveau ». Je sais bien
que candide l'a fait, le rappel est plutôt pour les autres lecteurs. ]

Bien. Donc tu as trouvé une faute mineure (qui n'a pas d'influence sur le
résultat, mais est effectivement discordante avec certains prémisses) dans
un livre publié il y a 17 ans. En dehors du fait que tu pourrais remonter la
remarque à qui de droit (ce qui risque d'avoir plus d'effet que de
déclencher une flamewar sur Usenet), pourquoi devrait-ce être un problème
pour François ?


et pourtant la norme ANSI indique :

"2.1.2.2 (...) It can be
defined with no parameters:
int main(void) { /*...*/ }
or (...)"


Là, je ne vois pas le rapport. S'il y a un problème dans le code ci-dessus,
c'est parce qu'il enfreint les recommandations de 3.9.5, mais pas 2.1.2.2
qui est vérifiée.


même si je sais bien que ce n'est pas une obligation.


Qu'est ce qui est une obligation ?
(Il s'agit ici de te faire préciser ta pensée, il y a pour moi trois points
différents qui peuvent poser problème vis-à-vis des normes ISO sur ce sujet,
int, void et les formes de main).


Antoine


Avatar
candide
En news:47d93098$0$2858$, candide va escriure:

#include <stdio.h>

main()


NON,


« Non » quoi ?


Réponse : on ne devrait pas écrire ainsi.




Bien. Donc tu as trouvé une faute mineure (qui n'a pas d'influence sur le
résultat, mais est effectivement discordante avec certains prémisses) dans
un livre publié il y a 17 ans.


Cette faute ou prétendue telle n'a aucune importance pour moi, K&R n'a
pas à être infaillible, ce qui m'importe d'abord et avant tout la
qualité des explications fournies, et c'est essentiellement ça qui pêche
dans ce bouquin. C'est un reproche qui s'adresse beaucoup moins aux
auteurs du livre qu'à ceux qui l'encensent aveuglément, la K&Rmonanie a
le don de m'agacer.


En dehors du fait que tu pourrais remonter la
remarque à qui de droit (ce qui risque d'avoir plus d'effet que de
déclencher une flamewar sur Usenet), pourquoi devrait-ce être un problème
pour François ?


parce que la pratique correcte depuis C99 est de déclarer

int main (void)

comme je l'ai appris sur ce forum, et main doit renvoyer un entier, et
en plus pas n'importe lequel, et je pense que François en voyant écrit
les choses comme K&R l'écrit pourrait considérer que c'est la bonne
façon de faire.

Ça prouve en plus qu'il n'a pas configuré son compilateur comme il se
doit, c'est pourtant une des premières choses à faire quand on commence
à programmer en C, et il ne faut pas compter sur K&R pour recevoir ce
genre de conseil (et je ne le leur reproche pas d'ailleurs).




et pourtant la norme ANSI indique :

"2.1.2.2 (...) It can be
defined with no parameters:
int main(void) { /*...*/ }
or (...)"


Là, je ne vois pas le rapport. S'il y a un problème dans le code ci-dessus,
c'est parce qu'il enfreint les recommandations de 3.9.5, mais pas 2.1.2.2
qui est vérifiée.


Ça a quand même un rapport me semble-t-il (la forme de définition est
donnée) et, par ailleurs, j'avais cherché mais en vain une référence à
l'obsolescence qui figure comme tu le rappelles en 3.9.5.




même si je sais bien que ce n'est pas une obligation.


Qu'est ce qui est une obligation ?


Écrire int main(void) au lieu de main() n'était pas une obligation. Moi
je lis dans Harbison :

"Prior to C99, the return type of main was often omitted, defaulting to
int. This is no longer allowed."



Avatar
Antoine Leca
En news:47d9a0c4$0$21310$, candide va escriure:
En news:47d93098$0$2858$, candide va escriure:

#include <stdio.h>

main()


NON,


« Non » quoi ?


Réponse : on ne devrait pas écrire ainsi.


Avoue que c'est quand même plus clair en l'expliquant.


En dehors du fait que tu pourrais remonter la
remarque à qui de droit (ce qui risque d'avoir plus d'effet que de
déclencher une flamewar sur Usenet), pourquoi devrait-ce être un
problème pour François ?


parce que la pratique correcte depuis C99 est de déclarer


L'une des pratiques correctes. Il y a en a plusieurs, même si celle-ci est
probablement la meilleure d'entre elles.

Et oui, je sais, je chipote : parce que je ne comprend toujours pas pourquoi
certains (ce n'est pas orienté vers toi seulement) se focalise envers ce
genre de raccourci, alors même que le code original était correct (en C89).


Une question un peu différente est d'expliquer pourquoi il faut éviter
void main()
[même si dans la pratique cela fonctionne partout, c'est nettement moins «
correct » que main() tout seul, main(void) ou int main(). ]


Ça prouve en plus qu'il n'a pas configuré son compilateur comme il se
doit, c'est pourtant une des premières choses à faire quand on
commence à programmer en C


Très juste.

et pourtant la norme ANSI indique :
"2.1.2.2 (...)
Là, je ne vois pas le rapport. S'il y a un problème dans le code

ci-dessus, c'est parce qu'il enfreint les recommandations de 3.9.5,
mais pas 2.1.2.2 qui est vérifiée.


Ça a quand même un rapport me semble-t-il (la forme de définition est
donnée)


Oui, mais pas avec le fait que
main()
ne soit pas « correct », qui était mon prémisse. Le problème était que
n'ayant pas compris la raison du « NON », j'ai supposé (à tort) que tu avais
relevé une incohérence dans le texte de K&R2, qui déclare se réferrer à la
norme mais ne respecte pas ce qu'elle dit à propos de l'obsolescence de la
forme sans void.

et, par ailleurs, j'avais cherché mais en vain une référence à
l'obsolescence qui figure comme tu le rappelles en 3.9.5.


D'après une lecture stricte de la norme ISO (principe général, éviter les
constructions déclarée obsolètes), il ne faut pas écrire
main() {
mais plutôt
main(void) {
L'effet est exactement identique (tant qu'il n'y a pas de référence
récursive à main()), mais il y a un léger souci de conformité.


même si je sais bien que ce n'est pas une obligation.


Qu'est ce qui est une obligation ?


Écrire int main(void) au lieu de main() n'était pas une obligation.
Moi je lis dans Harbison :

"Prior to C99, the return type of main was often omitted, defaulting
to int. This is no longer allowed."


Très bon rappel, lui aussi aurait été utile dès le début àmha.


Antoine




Avatar
Thierry B.
--{ candide a plopé ceci: }--

parce que la pratique correcte depuis C99 est de déclarer

int main (void)


Bonjour l'autisme des logiciels :)


--
http://la.buvette.org/ego/

Avatar
Vincent Lefevre
Dans l'article <fre43i$k1f$,
Antoine Leca écrit:

Une question un peu différente est d'expliquer pourquoi il faut éviter
void main()
[même si dans la pratique cela fonctionne partout, c'est nettement moins «
correct » que main() tout seul, main(void) ou int main(). ]


Ça ne fonctionne pas sous Linux:

vin% cat tst.sh
#!/bin/sh

set -e
echo 'void main() { }' > tst.c
gcc -Wall -O2 tst.c -o tst
./tst
echo OK
vin% ./tst.sh
tst.c:1: warning: return type of 'main' is not 'int'
vin%

Le script aurait dû afficher "OK".

--
Vincent Lefèvre - Web: <http://www.vinc17.org/>
100% accessible validated (X)HTML - Blog: <http://www.vinc17.org/blog/>
Work: CR INRIA - computer arithmetic / Arenaire project (LIP, ENS-Lyon)

1 2