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

EOF feof

9 réponses
Avatar
Gilles DRIDI
Bonsoir,

Y a-t-il un grand gourou qui pourra me dire pourquoi il faut toujours lire
un caractère avant
que feof renvoie vrai si le fichier est vide où si l'on a atteint la fin du
fichier ?

#include <stdio.h>
int main() {
FILE * fdesc;
char c;
if ( !(fdesc= fopen("toto.txt", "r")) ) {
perror("ouverture de \"toto.txt\"\n");
exit(-1);
}
c= fgetc(fdesc); // pourquoi cette ligne là ? (lire plus bas)
if ( feof(fdesc) ) printf("toto vide");
return 0;
}

On créer un fichier vide toto.txt par la commande
$cat >toto.txt
Ctrl-D

Dissertation : je suis d'accord pour dire que mécaniquement on ne peut pas
savoir si l'on a atteint la fin de fichier avant d'avoir "accéder" au
fichier. Mais, alors, pourquoi permettre d'utiliser la fonction feof() avant
d'avoir "accéder" au fichier (i.e. d'utiliser getc()) ? Juste Non ?

C++ ne résoud pas le problème...

Et Java ? Pouvez-vous me répondre en me donnant un bout de code Java.

Thanks ;-)

P.S. : en gros ça marche seulement parce qu'un gars à programmer feof()
comme cela !

9 réponses

Avatar
James Kanze
On Jun 16, 7:35 pm, "Gilles DRIDI" wrote:

Y a-t-il un grand gourou qui pourra me dire pourquoi il faut toujours lire
un caractère avant
que feof renvoie vrai si le fichier est vide où si l'on a atteint la fi n du
fichier ?


Oui. En C++, ce n'est pas garanti, on peut avoir file.eof() vrai
ou faux, mais en C, feof() ne devient vrai qu'après l'échec
d'une lecture. Et dans la pratique, c'est ce qu'on aurait en
fait en C++ aussi.

#include <stdio.h>
int main() {
FILE * fdesc;
char c;
if ( !(fdesc= fopen("toto.txt", "r")) ) {
perror("ouverture de "toto.txt"n");
exit(-1);
}
c= fgetc(fdesc); // pourquoi cette ligne là ? (lire plus bas)
if ( feof(fdesc) ) printf("toto vide");
return 0;
}

On créer un fichier vide toto.txt par la commande
$cat >toto.txt
Ctrl-D

Dissertation : je suis d'accord pour dire que mécaniquement on ne peut pas
savoir si l'on a atteint la fin de fichier avant d'avoir "accéder" au
fichier. Mais, alors, pourquoi permettre d'utiliser la fonction feof() av ant
d'avoir "accéder" au fichier (i.e. d'utiliser getc()) ? Juste Non ?


Pourquoi pas ? Pourquoi interdit l'appel ?

C++ ne résoud pas le problème...


Quel problème ?

Et Java ?


Les mêmes règles que C et C++, sans doute.

Pouvez-vous me répondre en me donnant un bout de code Java.

Thanks ;-)

P.S. : en gros ça marche seulement parce qu'un gars à
programmer feof() comme cela !


Ça marche comment ? En gros, feof() n'est vrai que suite à une
lecture système qui l'a renvoyé. Tant qu'on n'a pas essayé de
lire au niveau système (read() sous Posix, etc.), l'auteur de la
bibliothèque n'a aucun moyen de savoir si la lecteur va échouer
ou non. Et on ne peut pas essayer de lire avant que le programme
ne le démande, c-à-d un fgetc() ou quelque chose de semblable.

--
James Kanze (Gabi Software) email:
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Avatar
Marc Boyer
Le 16-06-2007, Gilles DRIDI a écrit :
Y a-t-il un grand gourou qui pourra me dire pourquoi il faut toujours lire
un caractère avant
que feof renvoie vrai si le fichier est vide où si l'on a atteint la fin du
fichier ?


Parce que quelqu'un peut écrire dans le fichier pendant que tu lis...
En fait, en C (car le code que tu postes est surtout du C, d'où mon
cros-post et le fu2), on lit dans un 'flux' qui peut être autre
chose qu'un fichier (cf stdin, stdout, sdterr).

Imagine deux processus en train de communiquer par des flux.
Ce n'est pas parce que le flux est vide à un moment qu'il
le sera plus tard.

Dissertation : je suis d'accord pour dire que mécaniquement on ne peut pas
savoir si l'on a atteint la fin de fichier avant d'avoir "accéder" au
fichier. Mais, alors, pourquoi permettre d'utiliser la fonction feof() avant
d'avoir "accéder" au fichier (i.e. d'utiliser getc()) ? Juste Non ?


Je ne comprends pas ta remarque.

P.S. : en gros ça marche seulement parce qu'un gars à programmer feof()
comme cela !


Il y a des choses ce ce genre dans les normes oui. Et la compatibilité
ascendante fait que ce serait trop dangeureux de changer...

Marc Boyer
--
Si tu peux supporter d'entendre tes paroles
Travesties par des gueux pour exciter des sots
IF -- Rudyard Kipling (Trad. André Maurois)

Avatar
Olivier Miakinen

Et Java ?


Les mêmes règles que C et C++, sans doute.


Une question récente dans fr.comp.lang.php me permet d'affirmer que
c'est la même chose en PHP.


Avatar
James Kanze
On Jun 18, 9:41 am, Marc Boyer
wrote:

Y a-t-il un grand gourou qui pourra me dire pourquoi il faut toujours l ire
un caractère avant
que feof renvoie vrai si le fichier est vide où si l'on a atteint la fin du
fichier ?


Parce que quelqu'un peut écrire dans le fichier pendant que tu lis...
En fait, en C (car le code que tu postes est surtout du C, d'où mon
cros-post et le fu2), on lit dans un 'flux' qui peut être autre
chose qu'un fichier (cf stdin, stdout, sdterr).

Imagine deux processus en train de communiquer par des flux.
Ce n'est pas parce que le flux est vide à un moment qu'il
le sera plus tard.


Historiquement, je crois que le problème était les entrées
interactives, avec un clavier. Dans beaucoup des case, les
stratégies à la Pascal, avec un EOF prévisionnel, resultaient en
une lecture (blocante, évidemment) avant qu'on ait sorti le
prompte.

--
James Kanze (GABI Software, from CAI) email:
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34


Avatar
Charlie Gordon
"James Kanze" a écrit dans le message de news:

On Jun 18, 9:41 am, Marc Boyer
wrote:

Y a-t-il un grand gourou qui pourra me dire pourquoi il faut toujours
lire
un caractère avant
que feof renvoie vrai si le fichier est vide où si l'on a atteint la fin
du
fichier ?


Parce que quelqu'un peut écrire dans le fichier pendant que tu lis...
En fait, en C (car le code que tu postes est surtout du C, d'où mon
cros-post et le fu2), on lit dans un 'flux' qui peut être autre
chose qu'un fichier (cf stdin, stdout, sdterr).

Imagine deux processus en train de communiquer par des flux.
Ce n'est pas parce que le flux est vide à un moment qu'il
le sera plus tard.


C'est beaucoup plus simple que cela : feof() ne fait que lire l'indicateur
de fin de fichier, comme ferr() lit l'indicateur d'erreur d'un FILE *
Ce sont les fonctions d'entrée/sortie qui positionnent ces indicateurs :
getc(), fgetc(), fgets(), fread(), fscanf()... pour la lecture. Donc tant
qu'on a pas fait d'entrées / sorties, les indicateurs ne sont pas
significatifs.
Pour utiliser correctement les FILE *, il est vivement recommandé de suivre
les exemples idiomatiques classiques, tels qu'exposés par Kernighan et
Ritchie, et d'oublier toute référence au Pascal et autres Basic qui ont une
autre philosophie.

Chqrlie.


Avatar
Marc Boyer
Le 19-06-2007, Charlie Gordon a écrit :

"James Kanze" a écrit dans le message de news:

On Jun 18, 9:41 am, Marc Boyer
wrote:

Y a-t-il un grand gourou qui pourra me dire pourquoi il faut toujours
lire
un caractère avant
que feof renvoie vrai si le fichier est vide où si l'on a atteint la fin
du
fichier ?


Parce que quelqu'un peut écrire dans le fichier pendant que tu lis...
En fait, en C (car le code que tu postes est surtout du C, d'où mon
cros-post et le fu2), on lit dans un 'flux' qui peut être autre
chose qu'un fichier (cf stdin, stdout, sdterr).

Imagine deux processus en train de communiquer par des flux.
Ce n'est pas parce que le flux est vide à un moment qu'il
le sera plus tard.


C'est beaucoup plus simple que cela : feof() ne fait que lire l'indicateur
de fin de fichier, comme ferr() lit l'indicateur d'erreur d'un FILE *


Mais ça, c'est de l'implantation qui correspond à un choix sémantique.
On aurait pu implanter feof comme

int guess_feof(FILE* f){
int c= getc(f);
int res= c != EOF;
ungetc(c, f);
return res;
}

Pour utiliser correctement les FILE *, il est vivement recommandé de suivre
les exemples idiomatiques classiques, tels qu'exposés par Kernighan et
Ritchie, et d'oublier toute référence au Pascal et autres Basic qui ont une
autre philosophie.


oui.

Marc Boyer
--
Si tu peux supporter d'entendre tes paroles
Travesties par des gueux pour exciter des sots
IF -- Rudyard Kipling (Trad. André Maurois)



Avatar
Antoine Leca
En news:,
Marc Boyer va escriure:

"James Kanze" a écrit dans le message de
news:
On Jun 18, 9:41 am, Marc Boyer wrote:

Y a-t-il un grand gourou qui pourra me dire pourquoi il faut
toujours lire un caractère avant
que feof renvoie vrai si le fichier est vide où si l'on a atteint
la fin du fichier ?


Parce que quelqu'un peut écrire dans le fichier pendant que tu
lis... En fait, en C (car le code que tu postes est surtout du C,
d'où mon cros-post et le fu2), on lit dans un 'flux' qui peut être
autre chose qu'un fichier (cf stdin, stdout, sdterr).

Imagine deux processus en train de communiquer par des flux.
Ce n'est pas parce que le flux est vide à un moment qu'il
le sera plus tard.


C'est beaucoup plus simple que cela : feof() ne fait que lire
l'indicateur de fin de fichier, comme ferr() lit l'indicateur
d'erreur d'un FILE *


Mais ça, c'est de l'implantation qui correspond à un choix
sémantique.


Pas sûr d'être d'accord, donc on va essayer de reformuler...

On aurait pu implanter feof comme

int guess_feof(FILE* f){
int c= getc(f);
int res= c != EOF;
ungetc(c, f);
return res;
}


Si tu fais cela sur un flux dynamique (pas un fichier, disons un socket pour
fixer les idées), tu vas faire une lecture (bloquante) juste pour savoir si
le flux est vide... ou alors, il y a quelque part, plus bas, un select()
avec un délai d'attente pour éviter de bloquer...
Bref, ta solution essaye de déterminer l'état _actuel_ du flux, et cela peut
prendre pas mal de temps.

En C, feof() ne signifie pas cela : c'est, comme ferror(), un compte-rendu
du résultat de l'opération précédente. Et la réponse est immédiate.


Et oui, c'est très différent de la sémantique de la fonction EoF() ou EOF
que l'on trouve dans d'autres langages de la même génération. C'est
probablement pour cela qu'ils n'ont pas le même nom :^)


Antoine




Avatar
Marc Boyer
Le 20-06-2007, Antoine Leca a écrit :
En news:,
Marc Boyer va escriure:

"James Kanze" a écrit dans le message de
news:
On Jun 18, 9:41 am, Marc Boyer wrote:

Y a-t-il un grand gourou qui pourra me dire pourquoi il faut
toujours lire un caractère avant
que feof renvoie vrai si le fichier est vide où si l'on a atteint
la fin du fichier ?


Parce que quelqu'un peut écrire dans le fichier pendant que tu
lis... En fait, en C (car le code que tu postes est surtout du C,
d'où mon cros-post et le fu2), on lit dans un 'flux' qui peut être
autre chose qu'un fichier (cf stdin, stdout, sdterr).

Imagine deux processus en train de communiquer par des flux.
Ce n'est pas parce que le flux est vide à un moment qu'il
le sera plus tard.


C'est beaucoup plus simple que cela : feof() ne fait que lire
l'indicateur de fin de fichier, comme ferr() lit l'indicateur
d'erreur d'un FILE *


Mais ça, c'est de l'implantation qui correspond à un choix
sémantique.


Pas sûr d'être d'accord, donc on va essayer de reformuler...


Je peux reformuler moi même: un choix a été fait, celui
de détecter la fin de flux *après* l'échec d'une lecture.
Car détecter le futur est difficile, puisqu'on peut être
'au moment du test' à la fin, mais il y aura peut-etre quelque
chose à la prochaine lecture.

On aurait pu implanter feof comme

int guess_feof(FILE* f){
int c= getc(f);
int res= c != EOF;
ungetc(c, f);
return res;
}


Si tu fais cela sur un flux dynamique (pas un fichier, disons un socket pour
fixer les idées), tu vas faire une lecture (bloquante) juste pour savoir si
le flux est vide... ou alors, il y a quelque part, plus bas, un select()
avec un délai d'attente pour éviter de bloquer...
Bref, ta solution essaye de déterminer l'état _actuel_ du flux, et cela peut
prendre pas mal de temps.


Oui, c'est ce que j'essayais de dire dans un post plus haut dans la
hiérarchie.
Je contestais juste la démache de Charlie qui expliquait la sémantique
par un choix d'implantation.

Marc Boyer
--
Si tu peux supporter d'entendre tes paroles
Travesties par des gueux pour exciter des sots
IF -- Rudyard Kipling (Trad. André Maurois)





Avatar
Antoine Leca
En news:,
Marc Boyer va escriure:
En news:,
Marc Boyer va escriure:
Mais ça, c'est de l'implantation qui correspond à un choix
sémantique.


Pas sûr d'être d'accord, donc on va essayer de reformuler...


Je peux reformuler moi même: un choix a été fait, celui
de détecter la fin de flux *après* l'échec d'une lecture.


Ce qui me gêne (je crois), c'est l'idée que tu peux véhiculer (je sais que
tu sais, c'est la forme qui m'importe ici) que feof() /détecte/ quelque
chose. Pour moi, feof() ne /détecte/ rien, elle ne fait que *constater*,
c'est seulement du sucre syntaxique.

(En fait, il est parfois nécessaire d'avoir soit feof() soit ferror() pour
pouvoir décider entre les deux conditions d'erreur, qui sinon se manifestent
toutes les deux par un retour EOF à la dernière opération.)


Je contestais juste la démache de Charlie qui expliquait la
sémantique par un choix d'implantation.


J'avais plutôt lu le post de Chqrlie comme l'explication (historiquement
correcte) sur le fait que feof() et ferror() ne sont rien d'autre que du
sucre syntaxique pour déterminer et discriminer les drapeaux d'erreur (
(((p)->_flag&_IOEOF)!=0) ou idem avec _IOERR ), appelés /indicateurs de fin
de fichier/ (resp. /d'erreur/) dans la norme.


Ce qui est un vrai choix sémantique et d'implémentation, c'est celui d'avoir
défini la fin de fichier comme un cas d'erreur (parmi d'autres). C'est lié
aux choix d'Unix et de sa non-dépendance des spécificités des
entrées-sorties (ce que tu expliquais). Mais cela vient surtout de
l'expérience des programmeurs d'Unix, qui avait remarqué que l'on disjoint
souvent le traitement de la fin de fichier du traitement central, et qu'un
moyen _binaire_ de programmer cela est d'utiliser la sortie « cas d'erreur »
; d'où l'idiome

while( opér_entrée() != EOF ) /* ou >=0 */
{ }
/* on a fini de lire _ou_ il y a eu une erreur */
/* si on veut faire la différence, utiliser ferror()/feof() */
/* sinon, il n'y a plus rien à lire de toutes façons... */

C'est à opposer par exemple aux techniques modernes, où la fin de fichier
est un résultat normal des opérations d'entrées, normal mais différent du
cas habituel, tandis que les erreurs ont plutôt tendance à générer des
exceptions et autres mécanismes anormaux. Autrement dit, on a ici un
mécanisme ternaire :

try {
while( opér_entrée() != FINI )
{ }
/* c'est fini, et tout s'est bien passé */
on_ferme();
}
exception
when WRITE_ERROR => disk_full();
-- . . .


Antoine