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

comprendre getchar()

59 réponses
Avatar
bpascal123
Je trouve getchar() assez difficile =E0 comprendre. Au lieu de saisir du
clavier, getchar lit directement dans la m=E9moire? Presser une touche
du claver entraine un signal dans le bios qui "renvoie" ce signal dans
le kernel puis dans la m=E9moire (buffer) et de ce dernier est affich=E9
le caract=E8re de la touche press=E9e (par ex.: a) pr=E9c=E9demment. Par
contre le caract=E8re reste toujours dans le buffer mais dans la partie
"ancienne" du buffer. Dans la partie "neuve", se trouverait les
caract=E8res qui n'ont pas =E9t=E9 affich=E9s =E0 l'=E9cran ou trait=E9s d'=
une autre
mani=E8re.

Ce code d'apparence simple pour la saisie me laisse perplexe:

#include <stdio.h>

int main(void)
{
char c ;
c =3D getchar() ;

while ( c !=3D EOF )
{
putchar(c) ;
c =3D getchar() ;
}
return 0 ;
}

Je me demande si un petit apprentissage de l'assembleur jusqu'=E0
comprendre ce code, ne serait pas utile dans ce cas?

10 réponses

2 3 4 5 6
Avatar
Jean-Marc Bourguet
(David Remacle) writes:

Antoine Leca wrote:

Bonjour,

[...]
>
> En plus, il semble que bpascal étudie sur une machine Linux en s'aidant
> d'un livre écrit pour MSDOS. J'ai donc essayer d'attirer son attention
> sur le fait qu'il doive faire l'effort de s'abstraire à ce niveau.
> Et se concentrer sur les seules choses qui importent, sans chercher à
> essayer d'utiliser l'assembleur ou les tampons ou je-ne-sais-quoi.
>

Justement, quel livre (ou site) a par le K&R pour apprendre a programmer
en C sur Unix/Linux ?



Il y a trois choses a apprendre.

- Apprendre a programmer. Aucune idee. Le C comme premier langage, et
d'autant plus en auto-apprentissage, ne me semble pas un bon choix.

- Apprendre le C. Quand on sait programmer, K&R est un bon choix.
Apprendre a programmer et le C en meme temps, cf supra.

- Apprendre a programmer pour Unix -> Advanced Programming in the Unix
Environment de W. Richard Stevens est incontournable a mon avis.
N'enseigne ni le C ni la programmation meme si certains aspects sont
couverts.

A+

--
Jean-Marc
FAQ de fclc: http://www.levenez.com/lang/c/faq
Site de usenet-fr: http://www.usenet-fr.news.eu.org
Avatar
Samuel DEVULDER
Antoine Leca a écrit :
Samuel DEVULDER écrivit :

Par ailleurs l'écriture suivante:

char c = (char)fgetc(FLUX);
if(feof(FLUX)) break;

Me semble claire, et assez proche des API des autres langages qui ont
une fonctionnalité type feof.



... et ne marche pas en C parce qu'elle ne gère pas les cas d'erreurs
d'E/S,



Pour cela il y a ferror(). On a 2 concepts distincts: fin de fichier et
erreur de lecture. Donc 2 fonctions. Je trouve cela pas mal.

Parce qu'à l'inverse quand on retourne EOF *aussi* en cas d'erreur,
c'est sacrément ambigu et pas tellement mieux. Bon c'est peut être le
symbole "EOF" qui est mal choisi. "ERR" aurait été plus rationnel:
erreur de lecture parce que fichier disk cassé ou parce que lecture au
delà du dernier caractère. Du reste à la sortie de la boucle on est
quand même obligé de tester feof() et ferror() pour distinguer une vraie
erreur d'une fin de fichier normale.

Le seul soucis du code avec feof()/ferror() dans la boucle c'est une
perte de compacité du code (au profit d'une meilleure lisibilité) et
(très) légère perte de perf.. mais bon, face aux vitesse d'I/O c'est
parfaitement insignifiant.

et qu'elle n'essaie pas réellement de demander au système si on
est à la fin du fichier (elle ne fait que relire l'état précédent).



Ben non, elle signale qu'on a atteint la fin de fichier. C'est pareil
que "i++ < 20", quand on atteint 20, i vaut 21. Pour savoir si on a
atteint la fin de fichier, il faut aller voir au delà.

De plus, fonctionnellement il manque quelque chose au code ci-dessus, il
lit le dernier caractère mais n'en fait rien et sort immédiatement de la
boucle.



Normal, on vient de lire une fin de fichier: la valeur retournée par
fgetc() n'a pas de sens.

Bref, c'est pas du C.



Et pourtant si.

Il est ainsi plus simple de lire un code où la fin de fichier
se détecte via feof() plutot que de tantôt comparer le code de retour à
EOF, à 0, à -1 ou à NULL.



Si c'est pour faire une critique sur le manque d'orthogonalité de la
bibliothèque standard, je ne te contredirais pas, et cela ne s'arrête
pas à stdio d'ailleurs. Clairement la bibliothèque standard du C a été
écrite en marchant, au fur et à mesure des besoins ; l'inconvénient par
rapport à une bibliothèque parfaite inventée d'un coup par un aréopage
c'est le manque d'orthogonalité, l'avantage c'est que l'on est sûr que
cela peut fonctionner ; et avec le langage C tu as choisi ton camp.



L'idéal c'est que chacun fasse comme il le souhaite avec ses propre
critères. Mon propos était de rappeler que feof() existe et qu'il a
l'avantage de l'homogénéité face à tester EOF pour fgetc(), NULL pour
fgets(), "<0" pour fread(), tant de complications inutiles qui peuvent
perturber les débutants.

sam.
Avatar
espie
In article <4c20b1fd$0$23924$,
Samuel DEVULDER wrote:
Antoine Leca a écrit :
Samuel DEVULDER écrivit :



Par ailleurs l'écriture suivante:

char c = (char)fgetc(FLUX);
if(feof(FLUX)) break;

Me semble claire, et assez proche des API des autres langages qui ont
une fonctionnalité type feof.



... et ne marche pas en C parce qu'elle ne gère pas les cas d'erreurs
d'E/S,



Pour cela il y a ferror(). On a 2 concepts distincts: fin de fichier et
erreur de lecture. Donc 2 fonctions. Je trouve cela pas mal.

Parce qu'à l'inverse quand on retourne EOF *aussi* en cas d'erreur,
c'est sacrément ambigu et pas tellement mieux. Bon c'est peut être le
symbole "EOF" qui est mal choisi. "ERR" aurait été plus rationnel:



C'est pas ambigu: ton stream te dit qu'il boude et qu'il ne te donnera
plus rien.

Dans des cas reels, tu vas sans doute verifier que ton entree est coherente,
et apres te preoccuper des diverses erreurs. D'ou ferror(). Note que fclose()
peut lui-aussi te poser des soucis.

Sur des cas reels, tant qu'on essaie pas d'aller a l'envers du langage et
de faire n'importe quoi d'autre, ca marche tout seul.

Oui, au final, le C est extremement dirigiste: il y a des idiomes qui marchent
bien... et le reste. Chaque fois que je tombe sur "le reste", j'ai l'impression
que le programmeur a essaye de reinventer son propre langage qui n'a rien
a voir avec le C (et generalement, ca n'est pas a l'avantage du programmeur...)

L'idéal c'est que chacun fasse comme il le souhaite avec ses propre
critères. Mon propos était de rappeler que feof() existe et qu'il a
l'avantage de l'homogénéité face à tester EOF pour fgetc(), NULL pour
fgets(), "<0" pour fread(), tant de complications inutiles qui peuvent
perturber les débutants.



inutiles ? faut voir.

perturber les debutants ? tot ou tard, ils seront perturbes. Il faut
quand meme un jour qu'ils enlevent les roulettes de leur petit velo...
ou alors qu'ils aillent faire autre chose...
Avatar
Jean-Marc Bourguet
Samuel DEVULDER writes:

Antoine Leca a écrit :
> Samuel DEVULDER écrivit :

>> Par ailleurs l'écriture suivante:
>>
>> char c = (char)fgetc(FLUX);
>> if(feof(FLUX)) break;
>>
>> Me semble claire, et assez proche des API des autres langages qui ont
>> une fonctionnalité type feof.
> ... et ne marche pas en C parce qu'elle ne gère pas les cas d'erreurs
> d'E/S,

Pour cela il y a ferror(). On a 2 concepts distincts: fin de fichier et
erreur de lecture. Donc 2 fonctions. Je trouve cela pas mal.



Mais utiliser ferror et feof n'a du sens qu'apres avoir constate qu'une
lecture a echoue. Tout comme examine la valeur de errno n'a du sens
qu'apres qu'une erreur ait ete constatee par un autre moyen (sauf dans le
cas de quelques fonctions mathematiques ou l'idiome est de mettre errno a
0, appeler la fonction et verifier si errno est toujours a 0)

Parce qu'à l'inverse quand on retourne EOF *aussi* en cas d'erreur, c'est
sacrément ambigu et pas tellement mieux. Bon c'est peut être le symbole
"EOF" qui est mal choisi.



La on est d'accord.

Le seul soucis du code avec feof()/ferror() dans la boucle c'est une perte
de compacité du code (au profit d'une meilleure lisibilité) et (très)
légère perte de perf.. mais bon, face aux vitesse d'I/O c'est parfaitement
insignifiant.



Non, c'est qu'il est incorrect au moins avec scanf, fread et fgets (et si
j'ai bonne memoire c'est formellement le cas aussi avec fgetc mais je n'en
suis pas sur et je ne connais pas d'implementation qui utilise cette
latitude).

#include <stdio.h>

int main()
{
char buf[1024];
while (scanf("%sn", buf) == 1) {
if (feof(stdin)) {
printf("Scanf succeeded and feof is truen");
}
printf("Got %sn", buf);
}
if (ferror(stdin)) {
printf("Errorn");
} else if (feof(stdin)) {
printf("End of filen");
} else {
printf("Why?n");
}
return 0;
}

$ cat data
toto
titi
tutu
$ cat data | ./a.out
Got toto
Got titi
Scanf succeeded and feof is true
Got tutu
End of file

et c'est meme pas un fichier qui n'est pas termine par un 'n'.

L'idéal c'est que chacun fasse comme il le souhaite avec ses propre
critères. Mon propos était de rappeler que feof() existe et qu'il a
l'avantage de l'homogénéité face à tester EOF pour fgetc(), NULL pour
fgets(), "<0" pour fread(), tant de complications inutiles qui peuvent
perturber les débutants.



Non. cf supra. (Avec fread il faut comparer la valeur retournee avec la
taille du buffer, si elles sont differentes, il y a fin de fichier ou
erreur de lecture; c'est avec read(2) sous Unix qu'on peut avoir des
lectures partielles)

#include <stdio.h>

int main()
{
char buf[1024];
size_t sz;
while ((sz = fread(buf, 1, sizeof buf, stdin)) == sizeof buf) {
if (feof(stdin)) {
printf("fread succeeded and feof is truen");
}
printf("Got %sn", buf);
}
if (sz > 0) {
if (feof(stdin)) {
printf("fread partially succeeded and feof is truen");
}
printf("Got %sn", buf);
}
if (ferror(stdin)) {
printf("Errorn");
} else if (feof(stdin)) {
printf("End of filen");
} else {
printf("Why?n");
}
return 0;
}

$ cat data | ./a.out
fread partially succeeded and feof is true
Got toto
titi
tutu

End of file

A+
--
Jean-Marc
FAQ de fclc: http://www.levenez.com/lang/c/faq
Site de usenet-fr: http://www.usenet-fr.news.eu.org
Avatar
Samuel DEVULDER
Jean-Marc Bourguet a écrit :
Samuel DEVULDER writes:

Antoine Leca a écrit :
Samuel DEVULDER écrivit :
Par ailleurs l'écriture suivante:

char c = (char)fgetc(FLUX);
if(feof(FLUX)) break;

Me semble claire, et assez proche des API des autres langages qui ont
une fonctionnalité type feof.


... et ne marche pas en C parce qu'elle ne gère pas les cas d'erreurs
d'E/S,


Pour cela il y a ferror(). On a 2 concepts distincts: fin de fichier et
erreur de lecture. Donc 2 fonctions. Je trouve cela pas mal.



Mais utiliser ferror et feof n'a du sens qu'apres avoir constate qu'une
lecture a echoue.



Ah? Mon man n'indique rien de tel.

FEOF(3) NEWLIB

NAME
4.7 `feof'--test for end of file

SYNOPSIS
#include <stdio.h>
int feof(FILE *FP);

DESCRIPTION
`feof' tests whether or not the end of the file identified by
FP has been reached.

RETURNS
`feof' returns `0' if the end of file has not yet been reached;
if at end of file, the result is nonzero.

Il n'est aucunement fait mention qu'il faut *necessairement* avoir
constaté qu'une lecture a échouée. A priori feof() est exploitable quand
on veut et signale si oui ou non on a franchi la fin de fichier. En fait
c'est vraiment lui qui fait foi.

Parce qu'à l'inverse quand on retourne EOF *aussi* en cas d'erreur, c'est
sacrément ambigu et pas tellement mieux. Bon c'est peut être le symbole
"EOF" qui est mal choisi.



La on est d'accord.

Le seul soucis du code avec feof()/ferror() dans la boucle c'est une perte
de compacité du code (au profit d'une meilleure lisibilité) et (très)
légère perte de perf.. mais bon, face aux vitesse d'I/O c'est parfaitement
insignifiant.



Non, c'est qu'il est incorrect au moins avec scanf, fread et fgets (et si
j'ai bonne memoire c'est formellement le cas aussi avec fgetc mais je n'en
suis pas sur et je ne connais pas d'implementation qui utilise cette
latitude).

#include <stdio.h>

int main()
{
char buf[1024];
while (scanf("%sn", buf) == 1) {
if (feof(stdin)) {
printf("Scanf succeeded and feof is truen");
}
printf("Got %sn", buf);
}
if (ferror(stdin)) {
printf("Errorn");
} else if (feof(stdin)) {
printf("End of filen");
} else {
printf("Why?n");
}
return 0;
}

$ cat data
toto
titi
tutu
$ cat data | ./a.out
Got toto
Got titi
Scanf succeeded and feof is true



Oui normal, à ce point là du code on a bien franchi la fin de fichier.
Rien d'inattendu pour ce qui me concerne.

Got tutu
End of file

et c'est meme pas un fichier qui n'est pas termine par un 'n'.



Je ne comprends pas bien. Tu aurait voulu quoi au juste? Qu'en fin de
fichier scanf() retourne un buffer non rempli? C'est justement le cas si
tu lis passé le feof()==true.

J'ai un peu le sentiment que l'erreur, ou le hiatus, est de considérer
que scanf() retourne un truc en relation directe avec la fin de fichier.
En fait non elle dit combien d'éléments ont étés lu. Si elle en lit
moins ca n'est pas forcément lié à une fin de fichier, mais peut-etre au
format attendu qui n'est pas respecté.

J'ai du mal à voir une incohérence entre fscanf et fgetc vis à vis de
feof(). Dans tous les cas, comme l'indique la doc, feof() est vrai une
fois passé la fin de fichier.

En fait en écrivant cela je vois ce que tu veux me montrer. En fait ce
que tu dis c'est que la valeur de la data lue par fscanf() est valide
alors qu'on a recu un feof(), c'est bien ca? Oui ca doit etre cela.. je
vois le trouble sauf que c'est pas tellement feof() qui est incohérent
avec fscanf() mais plutôt l'inverse, ou mieux le fait de considérer
qu'il y ait une relation *directe* entre les 2 car finalement fscanf()
ne fait que dire "combien il a lu" et donc la validité du buffer.. et
feof() signale si oui ou non on est en fin de fichier: les deux pouvant
être vrais simultanément: on a bien lu tutu et atteint la fin de fichier
en même temps.

L'idéal c'est que chacun fasse comme il le souhaite avec ses propre
critères. Mon propos était de rappeler que feof() existe et qu'il a
l'avantage de l'homogénéité face à tester EOF pour fgetc(), NULL pour
fgets(), "<0" pour fread(), tant de complications inutiles qui peuvent
perturber les débutants.



Non. cf supra. (Avec fread il faut comparer la valeur retournee avec la
taille du buffer, si elles sont differentes, il y a fin de fichier ou
erreur de lecture; c'est avec read(2) sous Unix qu'on peut avoir des
lectures partielles)



Je ne parlais pas de fread(), mais oui tu as raisons. C'est la même
logique que fscanf. La fin de fichier se détecte sur feof(), mais pour
autant on peut aussi avoir lu le nombre d'éléments souhaités. Le retour
de fread() ne concerne que la validité des datas dans le buffer.


A+

sam.
Avatar
espie
In article <4c20d153$0$5344$,
Samuel DEVULDER wrote:
Ah? Mon man n'indique rien de tel.

FEOF(3) NEWLIB

NAME
4.7 `feof'--test for end of file

SYNOPSIS
#include <stdio.h>
int feof(FILE *FP);

DESCRIPTION
`feof' tests whether or not the end of the file identified by
FP has been reached.

RETURNS
`feof' returns `0' if the end of file has not yet been reached;
if at end of file, the result is nonzero.

Il n'est aucunement fait mention qu'il faut *necessairement* avoir
constaté qu'une lecture a échouée. A priori feof() est exploitable quand
on veut et signale si oui ou non on a franchi la fin de fichier. En fait
c'est vraiment lui qui fait foi.



Tatata! dans ce newsgroup, la documentation qui fait foi s'appelle
ISO/IEC 9899:1999

Et elle dit les choses tres differemment:

The feof function tests the end-of-file indicator for the stream pointed to
by stream.

Ca parle de "end-of-file indicator" en se gardant bien d'y attacher une
semantique particuliere...

Ca n'est pour rien s'il y a une *indirection*: le end-of-file indicator
est mentionne en 7.19.1 (records whether the end of file has been reached).

Note le "records" ! c'est une difference majeure! la norme te dit qu'il y a
un indicateur qui consigne si la fin de fichier a ete enregistree.

S'ensuivent un nombre important de references a cet indicateur, qui expliquent
tres precisement comment celui-ci fonctionne.

Je te renvoie en particulier a la description de fgetc, qui est on ne peut
plus claire.

En particulier, une exegese du texte montre bien que les auteur evitent
soigneusement de dire tout ce qui peut arriver a feof. Mais c'est autrement
plus precis et detaille que la doc de la NEWLIB...
Avatar
Jean-Marc Bourguet
Samuel DEVULDER writes:

Jean-Marc Bourguet a écrit :
> Samuel DEVULDER writes:
>
>> Antoine Leca a écrit :
>>> Samuel DEVULDER écrivit :
>>>> Par ailleurs l'écriture suivante:
>>>>
>>>> char c = (char)fgetc(FLUX);
>>>> if(feof(FLUX)) break;
>>>>
>>>> Me semble claire, et assez proche des API des autres langages qui ont
>>>> une fonctionnalité type feof.
>>> ... et ne marche pas en C parce qu'elle ne gère pas les cas d'erreurs
>>> d'E/S,
>> Pour cela il y a ferror(). On a 2 concepts distincts: fin de fichier et
>> erreur de lecture. Donc 2 fonctions. Je trouve cela pas mal.
> Mais utiliser ferror et feof n'a du sens qu'apres avoir constate qu'une
> lecture a echoue.

Ah? Mon man n'indique rien de tel.

FEOF(3) NEWLIB

NAME
4.7 `feof'--test for end of file

SYNOPSIS
#include <stdio.h>
int feof(FILE *FP);

DESCRIPTION
`feof' tests whether or not the end of the file identified by
FP has been reached.



Il manque la description complete de ce que signifie "the end of the file
has been reached". La norme est plus claire, ca retourne la valeur d'un
indicateur persistant.

Il n'est aucunement fait mention qu'il faut *necessairement* avoir constaté
qu'une lecture a échouée. A priori feof() est exploitable quand on veut et
signale si oui ou non on a franchi la fin de fichier. En fait c'est
vraiment lui qui fait foi.



Oui, il a une definition. Quant a etre exploitable, c'est le point que je
conteste.

Quand feof retourne vrai, tu es sur que l'entree qui suit va echouer. Du
moins si ton implementation suit C99 sur ce point, C90 n'etait pas clair et
au moins certaines implementations n'ont pas ce comportement (Linux,
Solaris et AIX ne l'ont pas dans les versions installees ici quand l'entree
est un terminal). Quand il retourne faux, tu ne peux rien predire.

Donc en pratique, le seul moyen d'utiliser feof, c'est apres une entree qui
a echoue pour determiner pourquoi. Eventuellement, tu peux aussi t'en
servir pour contourner les problemes causes par la non conformite a C99 de
certaines implementations et le tester avant une entree.

A lire la suite, je crois qu'on a fini par se comprendre. Pour etre clair,
je dis que la structure a utiliser pour lire, c'est

while (io succeed) {
...
}
if (ferror()) {
// IO error
} else if (feof()) {
// End of file
} else {
// format error (scanf only)
}

(en passant, on voit un cas ou feof est a utiliser, il permet de discerner
une fin de fichier et un probleme de formatage -- j'ai tendance a ne pas
utiliser fscanf et a oublier ses particularites -- mais attention, apres un
probleme de formatage on peut avoir feof a vrai aussi) et les autres
structures, en particulier celles qui utilisent feof pour controler la
boucle comme

for (;;) {
scanf/getc/gets/fread
if (feof()) break;
...
}

ou
while (!feof()) {
scanf/getc/gets/fread
...
}

au mieux ne sont pas idiomatiques (peut-etre le premier cas avec fgetc mais
je n'en suis pas sur), au pire sont problematiques (le deuxieme cas
toujours, le premier cas avec fread, fscanf suivant la chaine de format,
fgets et les fichiers non termine par 'n', ...)

je vois le trouble sauf que c'est pas tellement feof() qui est incohérent
avec fscanf() mais plutôt l'inverse,



Je ne vois pas d'incoherence, simplement que la maniere d'utiliser feof est
pour classifier une situation connue, pas la detecter. A nouveau, le
parallele avec errno est valide.

A+

--
Jean-Marc
FAQ de fclc: http://www.levenez.com/lang/c/faq
Site de usenet-fr: http://www.usenet-fr.news.eu.org
Avatar
Antoine Leca
Samuel DEVULDER écrivit :
Je ne comprends pas bien.



Si je veux faire rire, j'isole cette phrase...


Je ne comprends pas bien. Tu aurait voulu quoi au juste?



Ce que JE n'arrive pas à comprendre, c'est le propos de contester
l'utilisation de EOF, à remplacer par feof(), au motif que pour d'autres
fonctions la valeur retournée par la fonction d'ES dans le cas similaire
est NULL ou 0, alors même que l'utilisation de cette fonction peut
parfois amener des résultats incorrects.

Par exemple, si on reprend ta formulation légèrement modifiée :

s = fgets(s, sizeof s, FLUX);
if(feof(FLUX)) break;

Si la fin de fichier n'est pas « protégée » par un n, elle va être
mangée par le break... Un joli bogue silencieux, facile à oublier en
test, en attente d'un jeu de données imprévu pour le faire monter...


Qu'en fin de fichier scanf() retourne un buffer non rempli? C'est
justement le cas si tu lis passé le feof()==true.



Dans l'essai de Jean-Marc, scanf() a lu "tutu", et en même temps touché
la fin du fichier, donc l'indicateur est passé à 1 ; puis a rempli le
tampon avec tutu comme demandé. Ce n'est qu'au coup suivant où scanf()
va réessayer de lire, étant positionné à la fin du fichier cela va
échouer et donc retournera enfin EOF : mais à l'itération précédente il
pourra/devra traiter le tutu.


J'ai un peu le sentiment que l'erreur, ou le hiatus, est de considérer
que scanf() retourne un truc en relation directe avec la fin de fichier.



Voilà. C'est comme cela que fonctionne le C : la fin de fichier est une
condition « anormale », à traiter en sortie de boucle.


Jean-Marc Bourguet a écrit :
(Avec fread il faut comparer la valeur retournee avec la
taille du buffer, si elles sont differentes, il y a fin de fichier ou
erreur de lecture; c'est avec read(2) sous Unix qu'on peut avoir des
lectures partielles)





Je ne suis pas certain. À la différence de fwrite() qui spécifie que
The fwrite function returns [...] which will be
less than nmemb only if a write error is encountered.
^^^^
le texte pour fread n'a pas ce "only". Et je serais TRÈS surpris que ce
soit un oubli :-) en particulier avec la nécessité de supporter les
fichiers « à la MSDOS » où il faut après lecture convertir les CR+LF en
n, et aussi les fichiers « à la mainframe » où ce sont les de
bourrage en fin de record qui sont éliminés, même sur un fichier "rb"...


Antoine
Avatar
Samuel DEVULDER
Jean-Marc Bourguet a écrit :

DESCRIPTION
`feof' tests whether or not the end of the file identified by
FP has been reached.



Il manque la description complete de ce que signifie "the end of the file
has been reached". La norme est plus claire, ca retourne la valeur d'un
indicateur persistant.



Oui, et c'est bien comme cela que le je comprends.

Il n'est aucunement fait mention qu'il faut *necessairement* avoir constaté
qu'une lecture a échouée. A priori feof() est exploitable quand on veut et
signale si oui ou non on a franchi la fin de fichier. En fait c'est
vraiment lui qui fait foi.



Oui, il a une definition. Quant a etre exploitable, c'est le point que je
conteste.



Ca serait quand même curieux que la doc utilisateur, le manpage, ne
donne pas l'info suffisante pour pouvoir utiliser feof(). Je ne vois pas
en quoi le fait que ce soit un indicateur persistant contredise le fait
qu'on puisse appeler feof() quand on veut, après une fonction qui échoue
ou pas, et que feof() retourne vrai si on a rencontré la fin de fichier.

Quand feof retourne vrai, tu es sur que l'entree qui suit va echouer.



Question con: est si on fait un fseek(), ca reset le eof? Et si on fait
un ungetc() ? J'imagine que la norme explique ces cas là qui sont plus
rares.

Du
moins si ton implementation suit C99 sur ce point, C90 n'etait pas clair et
au moins certaines implementations n'ont pas ce comportement (Linux,
Solaris et AIX ne l'ont pas dans les versions installees ici quand l'entree
est un terminal). Quand il retourne faux, tu ne peux rien predire.




Oui.. mais à aucun moment je n'écris if(!feof()). J'ai toujours écrit
if(feof()) c'est à dire utilisé la valeur vrai de l'indicateur.

Donc en pratique, le seul moyen d'utiliser feof, c'est apres une entree qui
a echoue pour determiner pourquoi.



Qui a échouée ou pas. Quoi qu'on fasse si feof() retourne vrai c'est
qu'on a atteint la fin de fichier. Peu importe ce que raconte la
fonction qui a échouée ou pas. Du reste la notion de fonction "échouée"
mériterait d'être correctement définie. Est-ce qu'un fread() qui
retourne 3 valeurs au lieu de 5 est un échec de la fonction? Je pense
pas. Par contre un fread() qui retourne EOF (il le peut), est assurément
clairement un echec (vu que EOF signifie echec de lecture finalement).

Eventuellement, tu peux aussi t'en
servir pour contourner les problemes causes par la non conformite a C99 de
certaines implementations et le tester avant une entree.



Le tester avant une entrée me semble quand même bizarre et ne figure pas
dans les cas que j'ai exposés.

A lire la suite, je crois qu'on a fini par se comprendre.



Oui je ne pense pas qu'il y ait de désaccord.

Pour etre clair,
je dis que la structure a utiliser pour lire, c'est

while (io succeed) {
...
}
if (ferror()) {
// IO error
} else if (feof()) {
// End of file
} else {
// format error (scanf only)
}



Oui.. mais encore il faut définir le "io_succed" comme il faut. Ca varie
de fonctions en fonctions.

Si on veut, et si le code s'y prète, on peut aussi mettre les tests sur
feof() à l'intérieur du while. Ce qui donne une écriture type do..while()

do {
char buf[1024]
if(NULL != fgets(buf, sizeof buf, FILE)) {
... traitement ...
}
} while(!feof(FILE));

Du coup on teste bien feof() et cela indépendamment de savoir si le
fgets() a marché ou pas. L'autre truc que j'aime bien c'est que le
buffer est déclaré localement du coup est n'est plus visible à
l'extérieur de la boucle de lecture. Le code est moins pollué avec des
vars hors contexte.

(en passant, on voit un cas ou feof est a utiliser, il permet de discerner
une fin de fichier et un probleme de formatage -- j'ai tendance a ne pas
utiliser fscanf et a oublier ses particularites -- mais attention, apres un
probleme de formatage on peut avoir feof a vrai aussi) et les autres
structures, en particulier celles qui utilisent feof pour controler la
boucle comme

for (;;) {
scanf/getc/gets/fread
if (feof()) break;
...
}

ou
while (!feof()) {
scanf/getc/gets/fread
...
}



Tes deux codes ne me semblent pas identiques.. Par contre

do {
scanf/getc/getc/fread
} while(!feof())

Me semble plus proche de la 1ere boucle. Attention toute fois à vérifier
que le scanf/getc/gets/fread retourne un truc qui signifie OK tout va
bien (cf le "NULL!=" dans le do..while() précédent).

au mieux ne sont pas idiomatiques (peut-etre le premier cas avec fgetc mais
je n'en suis pas sur), au pire sont problematiques (le deuxieme cas
toujours, le premier cas avec fread, fscanf suivant la chaine de format,
fgets et les fichiers non termine par 'n', ...)

je vois le trouble sauf que c'est pas tellement feof() qui est incohérent
avec fscanf() mais plutôt l'inverse,



Je ne vois pas d'incoherence, simplement que la maniere d'utiliser feof est
pour classifier une situation connue, pas la detecter.




C'est subtil dans la mesure ou la classification implique aussi la
détection.

A nouveau, le
parallele avec errno est valide.



On est d'accord.

a+

sam.
Avatar
Antoine Leca
Samuel DEVULDER écrivit :
Question con: est si on fait un fseek(), ca reset le eof?



Oui, si l'implémentation est conforme et si l'opération est possible, y
compris si tu es en fin de fichier (fopen(,"a"), fseek(,0L,SEEK_END))

Et si on fait un ungetc() ?



Oui.

J'imagine que la norme explique ces cas là qui sont plus rares.



Oui, et même des cas plus tordus, genre si tu lis des wchar_t...


Antoine
2 3 4 5 6