Jean-Marc Bourguet va escriure:Comme c'est le seul point que je pensais faire, je me demande ce que
tu me disputes.
Utiliser char (et non pas int) comme type pour les variables.
Jean-Marc Bourguet va escriure:
Comme c'est le seul point que je pensais faire, je me demande ce que
tu me disputes.
Utiliser char (et non pas int) comme type pour les variables.
Jean-Marc Bourguet va escriure:Comme c'est le seul point que je pensais faire, je me demande ce que
tu me disputes.
Utiliser char (et non pas int) comme type pour les variables.
En c107e3$pid$, Marc Boyer va escriure:Antoine Leca wrote:
if (isprint((unsigned char)c)) {
Au secours ! Transtypage indéfini !
Mais bon, imaginons le code
char c=rand()?'x':'1';
1) est-ce que ce code est bon ?
Défini « bon »
Correct : oui.
2) comment je peux tester que c'est un chiffre
avec isdigit ?
Bon, si tu as « typé » c en char, il faut effectivement, comme l'as écrit
Jean-Marc, transtyper en unsigned char. Sur ce point, il as parfaitement
raison, je ne le lui ai jamais disputé cela.
Pour ma culture, 'ÿ', c'est une constante de quel type ?
int (en C ; char en C++, c'est une différence entre les deux).
Mais bon, les caractères, c'est quoi finalement en C ?
Norme C (ici N869)
3.5 character
bit representation that fits in a byte
Ce qui nous mène à
3.4 byte
addressable unit of data storage large enough to hold any member of
the basic character set of the execution environment
Et ce machin (le basic bidule chouette environment), c'est défini par
l'implémentation, mais cela doit contenir tous les caractères imprimables
ASCII (sauf @ $ `), avec des représentations positives de surcroît. Tu auras
peut-être déduit que 'ÿ' peut donc avoir une représentation négative (c'est
la cas qu'évoquait Jean-Marc). Donc pour en revenir à ton exemple, avec ma
correction, si tu veux utiliser 'ÿ' à la place de ton 'x', et ensuite
pouvoir utiliser isdigit(), il faut écrire
int c = rand() ? (unsigned char)'ÿ' : '1';
L'arbre des types de ce bout de code est un poëme :
'ÿ' est un int, éventuellement négatif
(unsigned char)'ÿ' est un caractère non signé, donc positif
il est promu en int par (et pour) l'opération ? :
'1' est un int
le résultat de ? : est donc un int, pas de problème à ce niveau
on initialise un int avec un int, pas de problème non plus; notons c est
toujours positif, et peut-être passé à isdigit()
Dans le cas du code
char c = rand() ? 'ÿ' : '1';
'ÿ' est un int, éventuellement négatif (si char est signé)
'1' est un int (positif)
le résultat de ? : est donc un int, positif ou négatif
on initialise un char avec un int, il y a conversion; pas de changement de
signe intempestif cependant.
Si char est signé et 'ÿ' est encodé en Latin-1, c contient -1; si tu le
passes à isdigit(), tu as perdu.
Et si tu passes n'importe quel autre
caractère avec un encodage négatif, tu dois compter sur le bon vouloir de
l'implémentation pour te donner le comportement attendu (le comportement est
indéfini d'après la norme).
En c107e3$pid$1@news.cict.fr, Marc Boyer va escriure:
Antoine Leca wrote:
if (isprint((unsigned char)c)) {
Au secours ! Transtypage indéfini !
Mais bon, imaginons le code
char c=rand()?'x':'1';
1) est-ce que ce code est bon ?
Défini « bon »
Correct : oui.
2) comment je peux tester que c'est un chiffre
avec isdigit ?
Bon, si tu as « typé » c en char, il faut effectivement, comme l'as écrit
Jean-Marc, transtyper en unsigned char. Sur ce point, il as parfaitement
raison, je ne le lui ai jamais disputé cela.
Pour ma culture, 'ÿ', c'est une constante de quel type ?
int (en C ; char en C++, c'est une différence entre les deux).
Mais bon, les caractères, c'est quoi finalement en C ?
Norme C (ici N869)
3.5 character
bit representation that fits in a byte
Ce qui nous mène à
3.4 byte
addressable unit of data storage large enough to hold any member of
the basic character set of the execution environment
Et ce machin (le basic bidule chouette environment), c'est défini par
l'implémentation, mais cela doit contenir tous les caractères imprimables
ASCII (sauf @ $ `), avec des représentations positives de surcroît. Tu auras
peut-être déduit que 'ÿ' peut donc avoir une représentation négative (c'est
la cas qu'évoquait Jean-Marc). Donc pour en revenir à ton exemple, avec ma
correction, si tu veux utiliser 'ÿ' à la place de ton 'x', et ensuite
pouvoir utiliser isdigit(), il faut écrire
int c = rand() ? (unsigned char)'ÿ' : '1';
L'arbre des types de ce bout de code est un poëme :
'ÿ' est un int, éventuellement négatif
(unsigned char)'ÿ' est un caractère non signé, donc positif
il est promu en int par (et pour) l'opération ? :
'1' est un int
le résultat de ? : est donc un int, pas de problème à ce niveau
on initialise un int avec un int, pas de problème non plus; notons c est
toujours positif, et peut-être passé à isdigit()
Dans le cas du code
char c = rand() ? 'ÿ' : '1';
'ÿ' est un int, éventuellement négatif (si char est signé)
'1' est un int (positif)
le résultat de ? : est donc un int, positif ou négatif
on initialise un char avec un int, il y a conversion; pas de changement de
signe intempestif cependant.
Si char est signé et 'ÿ' est encodé en Latin-1, c contient -1; si tu le
passes à isdigit(), tu as perdu.
Et si tu passes n'importe quel autre
caractère avec un encodage négatif, tu dois compter sur le bon vouloir de
l'implémentation pour te donner le comportement attendu (le comportement est
indéfini d'après la norme).
En c107e3$pid$, Marc Boyer va escriure:Antoine Leca wrote:
if (isprint((unsigned char)c)) {
Au secours ! Transtypage indéfini !
Mais bon, imaginons le code
char c=rand()?'x':'1';
1) est-ce que ce code est bon ?
Défini « bon »
Correct : oui.
2) comment je peux tester que c'est un chiffre
avec isdigit ?
Bon, si tu as « typé » c en char, il faut effectivement, comme l'as écrit
Jean-Marc, transtyper en unsigned char. Sur ce point, il as parfaitement
raison, je ne le lui ai jamais disputé cela.
Pour ma culture, 'ÿ', c'est une constante de quel type ?
int (en C ; char en C++, c'est une différence entre les deux).
Mais bon, les caractères, c'est quoi finalement en C ?
Norme C (ici N869)
3.5 character
bit representation that fits in a byte
Ce qui nous mène à
3.4 byte
addressable unit of data storage large enough to hold any member of
the basic character set of the execution environment
Et ce machin (le basic bidule chouette environment), c'est défini par
l'implémentation, mais cela doit contenir tous les caractères imprimables
ASCII (sauf @ $ `), avec des représentations positives de surcroît. Tu auras
peut-être déduit que 'ÿ' peut donc avoir une représentation négative (c'est
la cas qu'évoquait Jean-Marc). Donc pour en revenir à ton exemple, avec ma
correction, si tu veux utiliser 'ÿ' à la place de ton 'x', et ensuite
pouvoir utiliser isdigit(), il faut écrire
int c = rand() ? (unsigned char)'ÿ' : '1';
L'arbre des types de ce bout de code est un poëme :
'ÿ' est un int, éventuellement négatif
(unsigned char)'ÿ' est un caractère non signé, donc positif
il est promu en int par (et pour) l'opération ? :
'1' est un int
le résultat de ? : est donc un int, pas de problème à ce niveau
on initialise un int avec un int, pas de problème non plus; notons c est
toujours positif, et peut-être passé à isdigit()
Dans le cas du code
char c = rand() ? 'ÿ' : '1';
'ÿ' est un int, éventuellement négatif (si char est signé)
'1' est un int (positif)
le résultat de ? : est donc un int, positif ou négatif
on initialise un char avec un int, il y a conversion; pas de changement de
signe intempestif cependant.
Si char est signé et 'ÿ' est encodé en Latin-1, c contient -1; si tu le
passes à isdigit(), tu as perdu.
Et si tu passes n'importe quel autre
caractère avec un encodage négatif, tu dois compter sur le bon vouloir de
l'implémentation pour te donner le comportement attendu (le comportement est
indéfini d'après la norme).
Tout cela n'est pas encore très clair pour moi...
2) comment je peux tester que c'est un chiffre
avec isdigit ?
Bon, si tu as « typé » c en char, il faut effectivement, comme l'as
écrit Jean-Marc, transtyper en unsigned char. Sur ce point, il as
parfaitement raison, je ne le lui ai jamais disputé cela.
Je cherche à comprendre pourquoi ne pas le transtyper serait faux.
Ca vient du fait qu'on a pas l'assurance que sizeof(int)>sizeof(char),
Parce que typer en char, ça a quand même l'avantage d'être
compatible avec les chaines char*, sinon ça repousse
juste le problème, non ?
Et les constantes comme 'x', on les nomme comment ?
Mon K&R parle de 'character constant'...
int c = rand() ? (unsigned char)'ÿ' : '1';
Là, je ne comprends plus: 'ÿ' est un entier. On peut
donc l'assigner à c sans perte d'information aucune.
C'est le bordel quand même, non ?
Bon, et maintenant que puis-je expliquer à des débutants
sans avoir à leur expliquer toutes les subtilités ?
1) si vous manipuler uniquement des caractères ASCII et
pas de fichiers, tout est simple, les caractères
sont des char
2) si vous manipuler uniquement des caractères ASCII et
des fichiers avec getc[har], vous devez d'abord vous
assurer que le retour est correct (soit en le stockant
dans un int et en le comparant à EOF, soit en le
stockant dans un char et en testant feof et ferror)
puis vous pouvez le mettre dans un char.
3) si vous travaillez dans la vraie vie où les caractères
peuvent avoir des accents, vous devez vous assurer
que les retour de getc[har] codent bien un caractère
(c'est à dire, soit différent de EOF), puis vous
pouver le stocker dans un char, mais l'utilisation
des isXXX demande qu'on écrive
isXXX( (unsigned char) param)
Dernière question, getc[har] ne pouvait pas retourner
EOF, est-ce qu'on aurait pas pu simplement lui faire
retourner un char, et avoir des isXXXX qui prennent
un char (ou unsigned char) en paramêtre ?
Tout cela n'est pas encore très clair pour moi...
2) comment je peux tester que c'est un chiffre
avec isdigit ?
Bon, si tu as « typé » c en char, il faut effectivement, comme l'as
écrit Jean-Marc, transtyper en unsigned char. Sur ce point, il as
parfaitement raison, je ne le lui ai jamais disputé cela.
Je cherche à comprendre pourquoi ne pas le transtyper serait faux.
Ca vient du fait qu'on a pas l'assurance que sizeof(int)>sizeof(char),
Parce que typer en char, ça a quand même l'avantage d'être
compatible avec les chaines char*, sinon ça repousse
juste le problème, non ?
Et les constantes comme 'x', on les nomme comment ?
Mon K&R parle de 'character constant'...
int c = rand() ? (unsigned char)'ÿ' : '1';
Là, je ne comprends plus: 'ÿ' est un entier. On peut
donc l'assigner à c sans perte d'information aucune.
C'est le bordel quand même, non ?
Bon, et maintenant que puis-je expliquer à des débutants
sans avoir à leur expliquer toutes les subtilités ?
1) si vous manipuler uniquement des caractères ASCII et
pas de fichiers, tout est simple, les caractères
sont des char
2) si vous manipuler uniquement des caractères ASCII et
des fichiers avec getc[har], vous devez d'abord vous
assurer que le retour est correct (soit en le stockant
dans un int et en le comparant à EOF, soit en le
stockant dans un char et en testant feof et ferror)
puis vous pouvez le mettre dans un char.
3) si vous travaillez dans la vraie vie où les caractères
peuvent avoir des accents, vous devez vous assurer
que les retour de getc[har] codent bien un caractère
(c'est à dire, soit différent de EOF), puis vous
pouver le stocker dans un char, mais l'utilisation
des isXXX demande qu'on écrive
isXXX( (unsigned char) param)
Dernière question, getc[har] ne pouvait pas retourner
EOF, est-ce qu'on aurait pas pu simplement lui faire
retourner un char, et avoir des isXXXX qui prennent
un char (ou unsigned char) en paramêtre ?
Tout cela n'est pas encore très clair pour moi...
2) comment je peux tester que c'est un chiffre
avec isdigit ?
Bon, si tu as « typé » c en char, il faut effectivement, comme l'as
écrit Jean-Marc, transtyper en unsigned char. Sur ce point, il as
parfaitement raison, je ne le lui ai jamais disputé cela.
Je cherche à comprendre pourquoi ne pas le transtyper serait faux.
Ca vient du fait qu'on a pas l'assurance que sizeof(int)>sizeof(char),
Parce que typer en char, ça a quand même l'avantage d'être
compatible avec les chaines char*, sinon ça repousse
juste le problème, non ?
Et les constantes comme 'x', on les nomme comment ?
Mon K&R parle de 'character constant'...
int c = rand() ? (unsigned char)'ÿ' : '1';
Là, je ne comprends plus: 'ÿ' est un entier. On peut
donc l'assigner à c sans perte d'information aucune.
C'est le bordel quand même, non ?
Bon, et maintenant que puis-je expliquer à des débutants
sans avoir à leur expliquer toutes les subtilités ?
1) si vous manipuler uniquement des caractères ASCII et
pas de fichiers, tout est simple, les caractères
sont des char
2) si vous manipuler uniquement des caractères ASCII et
des fichiers avec getc[har], vous devez d'abord vous
assurer que le retour est correct (soit en le stockant
dans un int et en le comparant à EOF, soit en le
stockant dans un char et en testant feof et ferror)
puis vous pouvez le mettre dans un char.
3) si vous travaillez dans la vraie vie où les caractères
peuvent avoir des accents, vous devez vous assurer
que les retour de getc[har] codent bien un caractère
(c'est à dire, soit différent de EOF), puis vous
pouver le stocker dans un char, mais l'utilisation
des isXXX demande qu'on écrive
isXXX( (unsigned char) param)
Dernière question, getc[har] ne pouvait pas retourner
EOF, est-ce qu'on aurait pas pu simplement lui faire
retourner un char, et avoir des isXXXX qui prennent
un char (ou unsigned char) en paramêtre ?
En c11unp$5t0$, Marc Boyer va escriure:Tout cela n'est pas encore très clair pour moi...
Ne t'inquiètes pas, tu progresses.
Mais c'est vrai que ces notions ne sont pas évidentes à saisir, surtout
qu'en plus je mélange (involontairement) les messages à destination des
débutants et les messages à destination des programmeurs confirmés.
Il y a un point que je pense tu dois commencer à entrevoir, c'est qu'il ne
faut pas mélanger char et "character". C'est très différent aujourd'hui en
C.
2) comment je peux tester que c'est un chiffre
avec isdigit ?
Bon, si tu as « typé » c en char, il faut effectivement, comme l'as
écrit Jean-Marc, transtyper en unsigned char. Sur ce point, il as
parfaitement raison, je ne le lui ai jamais disputé cela.
Je cherche à comprendre pourquoi ne pas le transtyper serait faux.
Problème de mathématique !
Le domaine de la fonction isdigit() est l'ensemble des valeurs de type char,
plus EOF. Comme on veut une injection, il faut que EOF soit disjoint des
valeurs assignés aux caractères. La convention, c'est que EOF est négatif,
et historiquement (c'est-à-dire presque partout) égal à (-1). Donc la
définition de la fonction impose que les valeurs des caractères qui sont
passées à isdigit(), soient positives (ou nulles).
Si tu le stockes dans un int, pas de problème, c'est directement bon, à
condition d'avoir pris la précaution de stocker la valeur positive dans la
variable int.
Ca vient du fait qu'on a pas l'assurance que sizeof(int)>sizeof(char),
En fait, la contrainte sur isdigit() est la meilleure preuve que
sizeof(int) > sizeof(char) [qui vaut 1].
Parce que typer en char, ça a quand même l'avantage d'être
compatible avec les chaines char*, sinon ça repousse
juste le problème, non ?
Parfaitement exact. Si tu types en int, et si tu as des chaînes en char*, il
faut transtyper (en unsigned char) au moment où tu extrais les caractères de
la chaîne.
6.4.4.4 Character constants
[2] An integer character constant is a sequence of one or more multibyte
characters enclosed in single-quotes, as in 'x' or 'ab'.
Semantics
[10] An integer character constant has type int. The value of an integer
character constant
containing a single character that maps to a member of the basic execution
character set is
the numerical value of the representation of the mapped character
interpreted as an
integer. The value of an integer character constant containing more than one
character, or
containing a character or escape sequence not represented in the basic
execution character
set, is implementation-defined.
Note: tu peux oublier pour le moment le fait d'avoir plusieurs caractères,
ainsi que la notion de "multibyte"; comme le dis la dernière phrase, de
toute manières c'est défini par l'implémentation.
Comme tu peux le voir, c'est tout sauf une définition simple et limpide.
int c = rand() ? (unsigned char)'ÿ' : '1';
Là, je ne comprends plus: 'ÿ' est un entier. On peut
donc l'assigner à c sans perte d'information aucune.
Sauf que comme ÿ est codé supérieur à 128, (signed char)'ÿ' et (unsigned
char)'ÿ' ont deux valeurs différentes¹. Par définition, 'ÿ' est égal à
(char)'ÿ', et vaut l'une ou l'autre des deux valeurs. Comme on veut être sûr
que la valeur stocké dans la variable soit positive, on est obligé de
transtyper.
Là, normalement, on se demande, mais pourquoi la norme ne dit pas que 'ÿ'
soit forcément la valeur positive ? la réponse, comme souvent, c'est la
nécessité de la compatibilité historique. Parce que les Américains, au tout
début, sur le fameux PDP11, utilisaient seulement l'ASCII, et donc D.
Ritchie a choisi de faire que char soit signé sur le premier compilateur C.
Dès le deuxième compilateur, qui devait pouvoir fonctionner sur une machine
EBCDIC (où '0' se code 240), le type char a été transformé en non signé.
C'était il y a 28 ans. Depuis, c'est le souk.
Bon, et maintenant que puis-je expliquer à des débutants
sans avoir à leur expliquer toutes les subtilités ?
1) si vous manipuler uniquement des caractères ASCII et
pas de fichiers, tout est simple, les caractères
sont des char
2) si vous manipuler uniquement des caractères ASCII et
des fichiers avec getc[har], vous devez d'abord vous
assurer que le retour est correct (soit en le stockant
dans un int et en le comparant à EOF, soit en le
stockant dans un char et en testant feof et ferror)
puis vous pouvez le mettre dans un char.
3) si vous travaillez dans la vraie vie où les caractères
peuvent avoir des accents, vous devez vous assurer
que les retour de getc[har] codent bien un caractère
(c'est à dire, soit différent de EOF), puis vous
pouver le stocker dans un char, mais l'utilisation
des isXXX demande qu'on écrive
isXXX( (unsigned char) param)
C'est trop compliqué.
1) Les caractères se stockent dans des int. Il n'y a aucun avantage, et
plutôt des inconvénients, à utiliser des variables char isolées. Le type
char est réservé aux chaînes de caractères, via les dérivés char[] et char*.
2) les fonctions de fichiers s'interfacent directement; pour voir s'il y a
une erreur, on compare avec EOF (qui est la seule valeur négative que peut
renvoyer fgetc et consorts)
3) idem avec isdigit() et compagnie; de plus, ces derniers se comportent «
bien » quand on leur founit EOF, et plus généralement le résultat de fgetc
et consorts
4) pour stocker un caractère (dans un int, donc) vers une chaîne char*, on
assigne directement [et oui, je sais que c'est défini par l'implémentation,
6.3.1.3p3]
5) pour extraire un caractère depuis une chaîne, il faut un transtypage en
unsigned char. Sinon un jour ou l'autre on aura le problème que signalait
Jean-Marc. C'est le seul point avec une difficulté.
ÀMHA, bien sûr.
6) si on manipule beaucoup de caractères accentués, on a avantage quand
c'est possible:
- soit à utiliser tout le temps unsigned char * à la place de char *
- soit à utiliser une option du compilateur pour forcer char à être non
signé. C'est moins dans l'esprit de la portabilité parce que cela va laisser
des problèmes le jour où le code devra fonctionner avec des char signés;
mais c'est plus simple à programmer.
Corrollaire du dernier point:
7) si on écrit une bibliothèque ou plus généralemnt du code destiné à être
réutilisé par quelqu'un d'autre, faire que dans son propre environnement
char soit signé et tester son code avec des caractères accentués; si c'est
bon dans ce cas-là, cela va aussi l'être dans les autres cas moins
problématiques. Notez que cela ne signifie pas obliger les utilisateurs de
la bibliothèque à utiliser des char signés.
Dernière question, getc[har] ne pouvait pas retourner
EOF, est-ce qu'on aurait pas pu simplement lui faire
retourner un char, et avoir des isXXXX qui prennent
un char (ou unsigned char) en paramêtre ?
Oui. Si tu continues dans ce chemin-là, tu obtiens Ada.
Bon, je me moques. Bien sûr, si getc pouvait signaler les cas d'erreur avec,
au hasard, une exception, dans le cas normal il pourrait renvoyer un char,
et fin du problème. Mais ce n'est plus (du tout) le même langage, et donc tu
perds la compatibilité avec tout le code qui existe, et qui a
fondamentalement besoin que les cas d'erreur en lecture soit indiqué par la
valeur de retour EOF (ou plus généralement une valeur négative) de la
fonction getc.
Le langage C est un compromis, ce n'est jamais parfait. Défendre C comme
étant « meilleur » est presque toujours une mauvaise option. En plus, comme
c'est maintenant un vieux langage (les ordinateurs électroniques ont 60 ans
cette année, C en a plus de 30 !), certains choix conceptuels sont
archaïques. Il faut faire avec.
En c11unp$5t0$1@news.cict.fr, Marc Boyer va escriure:
Tout cela n'est pas encore très clair pour moi...
Ne t'inquiètes pas, tu progresses.
Mais c'est vrai que ces notions ne sont pas évidentes à saisir, surtout
qu'en plus je mélange (involontairement) les messages à destination des
débutants et les messages à destination des programmeurs confirmés.
Il y a un point que je pense tu dois commencer à entrevoir, c'est qu'il ne
faut pas mélanger char et "character". C'est très différent aujourd'hui en
C.
2) comment je peux tester que c'est un chiffre
avec isdigit ?
Bon, si tu as « typé » c en char, il faut effectivement, comme l'as
écrit Jean-Marc, transtyper en unsigned char. Sur ce point, il as
parfaitement raison, je ne le lui ai jamais disputé cela.
Je cherche à comprendre pourquoi ne pas le transtyper serait faux.
Problème de mathématique !
Le domaine de la fonction isdigit() est l'ensemble des valeurs de type char,
plus EOF. Comme on veut une injection, il faut que EOF soit disjoint des
valeurs assignés aux caractères. La convention, c'est que EOF est négatif,
et historiquement (c'est-à-dire presque partout) égal à (-1). Donc la
définition de la fonction impose que les valeurs des caractères qui sont
passées à isdigit(), soient positives (ou nulles).
Si tu le stockes dans un int, pas de problème, c'est directement bon, à
condition d'avoir pris la précaution de stocker la valeur positive dans la
variable int.
Ca vient du fait qu'on a pas l'assurance que sizeof(int)>sizeof(char),
En fait, la contrainte sur isdigit() est la meilleure preuve que
sizeof(int) > sizeof(char) [qui vaut 1].
Parce que typer en char, ça a quand même l'avantage d'être
compatible avec les chaines char*, sinon ça repousse
juste le problème, non ?
Parfaitement exact. Si tu types en int, et si tu as des chaînes en char*, il
faut transtyper (en unsigned char) au moment où tu extrais les caractères de
la chaîne.
6.4.4.4 Character constants
[2] An integer character constant is a sequence of one or more multibyte
characters enclosed in single-quotes, as in 'x' or 'ab'.
Semantics
[10] An integer character constant has type int. The value of an integer
character constant
containing a single character that maps to a member of the basic execution
character set is
the numerical value of the representation of the mapped character
interpreted as an
integer. The value of an integer character constant containing more than one
character, or
containing a character or escape sequence not represented in the basic
execution character
set, is implementation-defined.
Note: tu peux oublier pour le moment le fait d'avoir plusieurs caractères,
ainsi que la notion de "multibyte"; comme le dis la dernière phrase, de
toute manières c'est défini par l'implémentation.
Comme tu peux le voir, c'est tout sauf une définition simple et limpide.
int c = rand() ? (unsigned char)'ÿ' : '1';
Là, je ne comprends plus: 'ÿ' est un entier. On peut
donc l'assigner à c sans perte d'information aucune.
Sauf que comme ÿ est codé supérieur à 128, (signed char)'ÿ' et (unsigned
char)'ÿ' ont deux valeurs différentes¹. Par définition, 'ÿ' est égal à
(char)'ÿ', et vaut l'une ou l'autre des deux valeurs. Comme on veut être sûr
que la valeur stocké dans la variable soit positive, on est obligé de
transtyper.
Là, normalement, on se demande, mais pourquoi la norme ne dit pas que 'ÿ'
soit forcément la valeur positive ? la réponse, comme souvent, c'est la
nécessité de la compatibilité historique. Parce que les Américains, au tout
début, sur le fameux PDP11, utilisaient seulement l'ASCII, et donc D.
Ritchie a choisi de faire que char soit signé sur le premier compilateur C.
Dès le deuxième compilateur, qui devait pouvoir fonctionner sur une machine
EBCDIC (où '0' se code 240), le type char a été transformé en non signé.
C'était il y a 28 ans. Depuis, c'est le souk.
Bon, et maintenant que puis-je expliquer à des débutants
sans avoir à leur expliquer toutes les subtilités ?
1) si vous manipuler uniquement des caractères ASCII et
pas de fichiers, tout est simple, les caractères
sont des char
2) si vous manipuler uniquement des caractères ASCII et
des fichiers avec getc[har], vous devez d'abord vous
assurer que le retour est correct (soit en le stockant
dans un int et en le comparant à EOF, soit en le
stockant dans un char et en testant feof et ferror)
puis vous pouvez le mettre dans un char.
3) si vous travaillez dans la vraie vie où les caractères
peuvent avoir des accents, vous devez vous assurer
que les retour de getc[har] codent bien un caractère
(c'est à dire, soit différent de EOF), puis vous
pouver le stocker dans un char, mais l'utilisation
des isXXX demande qu'on écrive
isXXX( (unsigned char) param)
C'est trop compliqué.
1) Les caractères se stockent dans des int. Il n'y a aucun avantage, et
plutôt des inconvénients, à utiliser des variables char isolées. Le type
char est réservé aux chaînes de caractères, via les dérivés char[] et char*.
2) les fonctions de fichiers s'interfacent directement; pour voir s'il y a
une erreur, on compare avec EOF (qui est la seule valeur négative que peut
renvoyer fgetc et consorts)
3) idem avec isdigit() et compagnie; de plus, ces derniers se comportent «
bien » quand on leur founit EOF, et plus généralement le résultat de fgetc
et consorts
4) pour stocker un caractère (dans un int, donc) vers une chaîne char*, on
assigne directement [et oui, je sais que c'est défini par l'implémentation,
6.3.1.3p3]
5) pour extraire un caractère depuis une chaîne, il faut un transtypage en
unsigned char. Sinon un jour ou l'autre on aura le problème que signalait
Jean-Marc. C'est le seul point avec une difficulté.
ÀMHA, bien sûr.
6) si on manipule beaucoup de caractères accentués, on a avantage quand
c'est possible:
- soit à utiliser tout le temps unsigned char * à la place de char *
- soit à utiliser une option du compilateur pour forcer char à être non
signé. C'est moins dans l'esprit de la portabilité parce que cela va laisser
des problèmes le jour où le code devra fonctionner avec des char signés;
mais c'est plus simple à programmer.
Corrollaire du dernier point:
7) si on écrit une bibliothèque ou plus généralemnt du code destiné à être
réutilisé par quelqu'un d'autre, faire que dans son propre environnement
char soit signé et tester son code avec des caractères accentués; si c'est
bon dans ce cas-là, cela va aussi l'être dans les autres cas moins
problématiques. Notez que cela ne signifie pas obliger les utilisateurs de
la bibliothèque à utiliser des char signés.
Dernière question, getc[har] ne pouvait pas retourner
EOF, est-ce qu'on aurait pas pu simplement lui faire
retourner un char, et avoir des isXXXX qui prennent
un char (ou unsigned char) en paramêtre ?
Oui. Si tu continues dans ce chemin-là, tu obtiens Ada.
Bon, je me moques. Bien sûr, si getc pouvait signaler les cas d'erreur avec,
au hasard, une exception, dans le cas normal il pourrait renvoyer un char,
et fin du problème. Mais ce n'est plus (du tout) le même langage, et donc tu
perds la compatibilité avec tout le code qui existe, et qui a
fondamentalement besoin que les cas d'erreur en lecture soit indiqué par la
valeur de retour EOF (ou plus généralement une valeur négative) de la
fonction getc.
Le langage C est un compromis, ce n'est jamais parfait. Défendre C comme
étant « meilleur » est presque toujours une mauvaise option. En plus, comme
c'est maintenant un vieux langage (les ordinateurs électroniques ont 60 ans
cette année, C en a plus de 30 !), certains choix conceptuels sont
archaïques. Il faut faire avec.
En c11unp$5t0$, Marc Boyer va escriure:Tout cela n'est pas encore très clair pour moi...
Ne t'inquiètes pas, tu progresses.
Mais c'est vrai que ces notions ne sont pas évidentes à saisir, surtout
qu'en plus je mélange (involontairement) les messages à destination des
débutants et les messages à destination des programmeurs confirmés.
Il y a un point que je pense tu dois commencer à entrevoir, c'est qu'il ne
faut pas mélanger char et "character". C'est très différent aujourd'hui en
C.
2) comment je peux tester que c'est un chiffre
avec isdigit ?
Bon, si tu as « typé » c en char, il faut effectivement, comme l'as
écrit Jean-Marc, transtyper en unsigned char. Sur ce point, il as
parfaitement raison, je ne le lui ai jamais disputé cela.
Je cherche à comprendre pourquoi ne pas le transtyper serait faux.
Problème de mathématique !
Le domaine de la fonction isdigit() est l'ensemble des valeurs de type char,
plus EOF. Comme on veut une injection, il faut que EOF soit disjoint des
valeurs assignés aux caractères. La convention, c'est que EOF est négatif,
et historiquement (c'est-à-dire presque partout) égal à (-1). Donc la
définition de la fonction impose que les valeurs des caractères qui sont
passées à isdigit(), soient positives (ou nulles).
Si tu le stockes dans un int, pas de problème, c'est directement bon, à
condition d'avoir pris la précaution de stocker la valeur positive dans la
variable int.
Ca vient du fait qu'on a pas l'assurance que sizeof(int)>sizeof(char),
En fait, la contrainte sur isdigit() est la meilleure preuve que
sizeof(int) > sizeof(char) [qui vaut 1].
Parce que typer en char, ça a quand même l'avantage d'être
compatible avec les chaines char*, sinon ça repousse
juste le problème, non ?
Parfaitement exact. Si tu types en int, et si tu as des chaînes en char*, il
faut transtyper (en unsigned char) au moment où tu extrais les caractères de
la chaîne.
6.4.4.4 Character constants
[2] An integer character constant is a sequence of one or more multibyte
characters enclosed in single-quotes, as in 'x' or 'ab'.
Semantics
[10] An integer character constant has type int. The value of an integer
character constant
containing a single character that maps to a member of the basic execution
character set is
the numerical value of the representation of the mapped character
interpreted as an
integer. The value of an integer character constant containing more than one
character, or
containing a character or escape sequence not represented in the basic
execution character
set, is implementation-defined.
Note: tu peux oublier pour le moment le fait d'avoir plusieurs caractères,
ainsi que la notion de "multibyte"; comme le dis la dernière phrase, de
toute manières c'est défini par l'implémentation.
Comme tu peux le voir, c'est tout sauf une définition simple et limpide.
int c = rand() ? (unsigned char)'ÿ' : '1';
Là, je ne comprends plus: 'ÿ' est un entier. On peut
donc l'assigner à c sans perte d'information aucune.
Sauf que comme ÿ est codé supérieur à 128, (signed char)'ÿ' et (unsigned
char)'ÿ' ont deux valeurs différentes¹. Par définition, 'ÿ' est égal à
(char)'ÿ', et vaut l'une ou l'autre des deux valeurs. Comme on veut être sûr
que la valeur stocké dans la variable soit positive, on est obligé de
transtyper.
Là, normalement, on se demande, mais pourquoi la norme ne dit pas que 'ÿ'
soit forcément la valeur positive ? la réponse, comme souvent, c'est la
nécessité de la compatibilité historique. Parce que les Américains, au tout
début, sur le fameux PDP11, utilisaient seulement l'ASCII, et donc D.
Ritchie a choisi de faire que char soit signé sur le premier compilateur C.
Dès le deuxième compilateur, qui devait pouvoir fonctionner sur une machine
EBCDIC (où '0' se code 240), le type char a été transformé en non signé.
C'était il y a 28 ans. Depuis, c'est le souk.
Bon, et maintenant que puis-je expliquer à des débutants
sans avoir à leur expliquer toutes les subtilités ?
1) si vous manipuler uniquement des caractères ASCII et
pas de fichiers, tout est simple, les caractères
sont des char
2) si vous manipuler uniquement des caractères ASCII et
des fichiers avec getc[har], vous devez d'abord vous
assurer que le retour est correct (soit en le stockant
dans un int et en le comparant à EOF, soit en le
stockant dans un char et en testant feof et ferror)
puis vous pouvez le mettre dans un char.
3) si vous travaillez dans la vraie vie où les caractères
peuvent avoir des accents, vous devez vous assurer
que les retour de getc[har] codent bien un caractère
(c'est à dire, soit différent de EOF), puis vous
pouver le stocker dans un char, mais l'utilisation
des isXXX demande qu'on écrive
isXXX( (unsigned char) param)
C'est trop compliqué.
1) Les caractères se stockent dans des int. Il n'y a aucun avantage, et
plutôt des inconvénients, à utiliser des variables char isolées. Le type
char est réservé aux chaînes de caractères, via les dérivés char[] et char*.
2) les fonctions de fichiers s'interfacent directement; pour voir s'il y a
une erreur, on compare avec EOF (qui est la seule valeur négative que peut
renvoyer fgetc et consorts)
3) idem avec isdigit() et compagnie; de plus, ces derniers se comportent «
bien » quand on leur founit EOF, et plus généralement le résultat de fgetc
et consorts
4) pour stocker un caractère (dans un int, donc) vers une chaîne char*, on
assigne directement [et oui, je sais que c'est défini par l'implémentation,
6.3.1.3p3]
5) pour extraire un caractère depuis une chaîne, il faut un transtypage en
unsigned char. Sinon un jour ou l'autre on aura le problème que signalait
Jean-Marc. C'est le seul point avec une difficulté.
ÀMHA, bien sûr.
6) si on manipule beaucoup de caractères accentués, on a avantage quand
c'est possible:
- soit à utiliser tout le temps unsigned char * à la place de char *
- soit à utiliser une option du compilateur pour forcer char à être non
signé. C'est moins dans l'esprit de la portabilité parce que cela va laisser
des problèmes le jour où le code devra fonctionner avec des char signés;
mais c'est plus simple à programmer.
Corrollaire du dernier point:
7) si on écrit une bibliothèque ou plus généralemnt du code destiné à être
réutilisé par quelqu'un d'autre, faire que dans son propre environnement
char soit signé et tester son code avec des caractères accentués; si c'est
bon dans ce cas-là, cela va aussi l'être dans les autres cas moins
problématiques. Notez que cela ne signifie pas obliger les utilisateurs de
la bibliothèque à utiliser des char signés.
Dernière question, getc[har] ne pouvait pas retourner
EOF, est-ce qu'on aurait pas pu simplement lui faire
retourner un char, et avoir des isXXXX qui prennent
un char (ou unsigned char) en paramêtre ?
Oui. Si tu continues dans ce chemin-là, tu obtiens Ada.
Bon, je me moques. Bien sûr, si getc pouvait signaler les cas d'erreur avec,
au hasard, une exception, dans le cas normal il pourrait renvoyer un char,
et fin du problème. Mais ce n'est plus (du tout) le même langage, et donc tu
perds la compatibilité avec tout le code qui existe, et qui a
fondamentalement besoin que les cas d'erreur en lecture soit indiqué par la
valeur de retour EOF (ou plus généralement une valeur négative) de la
fonction getc.
Le langage C est un compromis, ce n'est jamais parfait. Défendre C comme
étant « meilleur » est presque toujours une mauvaise option. En plus, comme
c'est maintenant un vieux langage (les ordinateurs électroniques ont 60 ans
cette année, C en a plus de 30 !), certains choix conceptuels sont
archaïques. Il faut faire avec.
Antoine Leca wrote:Le domaine de la fonction isdigit() est l'ensemble des valeurs de
type char, plus EOF. Comme on veut une injection, il faut que EOF
soit disjoint des valeurs assignés aux caractères. La convention,
c'est que EOF est négatif, et historiquement (c'est-à-dire presque
partout) égal à (-1). Donc la définition de la fonction impose que
les valeurs des caractères qui sont passées à isdigit(), soient
positives (ou nulles).
OK, alors que s'il avait été égal à INT_MIN, INT_MAX ou quoi que
ce soit en dehors de CHAR_MIN...CHAR_MAX, on était sauvé.
En fait, la contrainte sur isdigit() est la meilleure preuve que
sizeof(int) > sizeof(char) [qui vaut 1].
J'imaginais un monde ou, par exemple, char faisait 16 bits,
mais où les "characters constants" auraient été dans
un intervalle de taille 2^15. On gardait la place pour coder
EOF en dehors (ça laissait de la marge).
Transtyper en unsigned char ? A oui, sinon, 'ÿ' se retrouve en EOF
souvent...
int c = rand() ? (unsigned char)'ÿ' : '1';
Comme on veut être sûr que la valeur stocké dans la variable soit
positive, on est obligé de transtyper.
A cause du conflit de EOF.
Car s'il était encodé en dehors des
valeurs des "character constant", que ce soit positif ou négatif,
on s'en moquerait, car celui qui fournir les isXXXX est aussi
celui qui décide le signe de char, donc il a juste a être cohérent
avec lui même.
6) si on manipule beaucoup de caractères accentués, on a avantage
quand c'est possible:
- soit à utiliser tout le temps unsigned char * à la place de char
*
Et les str* de string.h fonctionnent encore ?
Je note surtout le conseil des caractères accentué[s].
J'ai pas pour but de leur faire écrire une bibliothèque.
Mon cours commence avec:
- le C est un vieux langage (1970), moderne à l'époque...
Antoine Leca wrote:
Le domaine de la fonction isdigit() est l'ensemble des valeurs de
type char, plus EOF. Comme on veut une injection, il faut que EOF
soit disjoint des valeurs assignés aux caractères. La convention,
c'est que EOF est négatif, et historiquement (c'est-à-dire presque
partout) égal à (-1). Donc la définition de la fonction impose que
les valeurs des caractères qui sont passées à isdigit(), soient
positives (ou nulles).
OK, alors que s'il avait été égal à INT_MIN, INT_MAX ou quoi que
ce soit en dehors de CHAR_MIN...CHAR_MAX, on était sauvé.
En fait, la contrainte sur isdigit() est la meilleure preuve que
sizeof(int) > sizeof(char) [qui vaut 1].
J'imaginais un monde ou, par exemple, char faisait 16 bits,
mais où les "characters constants" auraient été dans
un intervalle de taille 2^15. On gardait la place pour coder
EOF en dehors (ça laissait de la marge).
Transtyper en unsigned char ? A oui, sinon, 'ÿ' se retrouve en EOF
souvent...
int c = rand() ? (unsigned char)'ÿ' : '1';
Comme on veut être sûr que la valeur stocké dans la variable soit
positive, on est obligé de transtyper.
A cause du conflit de EOF.
Car s'il était encodé en dehors des
valeurs des "character constant", que ce soit positif ou négatif,
on s'en moquerait, car celui qui fournir les isXXXX est aussi
celui qui décide le signe de char, donc il a juste a être cohérent
avec lui même.
6) si on manipule beaucoup de caractères accentués, on a avantage
quand c'est possible:
- soit à utiliser tout le temps unsigned char * à la place de char
*
Et les str* de string.h fonctionnent encore ?
Je note surtout le conseil des caractères accentué[s].
J'ai pas pour but de leur faire écrire une bibliothèque.
Mon cours commence avec:
- le C est un vieux langage (1970), moderne à l'époque...
Antoine Leca wrote:Le domaine de la fonction isdigit() est l'ensemble des valeurs de
type char, plus EOF. Comme on veut une injection, il faut que EOF
soit disjoint des valeurs assignés aux caractères. La convention,
c'est que EOF est négatif, et historiquement (c'est-à-dire presque
partout) égal à (-1). Donc la définition de la fonction impose que
les valeurs des caractères qui sont passées à isdigit(), soient
positives (ou nulles).
OK, alors que s'il avait été égal à INT_MIN, INT_MAX ou quoi que
ce soit en dehors de CHAR_MIN...CHAR_MAX, on était sauvé.
En fait, la contrainte sur isdigit() est la meilleure preuve que
sizeof(int) > sizeof(char) [qui vaut 1].
J'imaginais un monde ou, par exemple, char faisait 16 bits,
mais où les "characters constants" auraient été dans
un intervalle de taille 2^15. On gardait la place pour coder
EOF en dehors (ça laissait de la marge).
Transtyper en unsigned char ? A oui, sinon, 'ÿ' se retrouve en EOF
souvent...
int c = rand() ? (unsigned char)'ÿ' : '1';
Comme on veut être sûr que la valeur stocké dans la variable soit
positive, on est obligé de transtyper.
A cause du conflit de EOF.
Car s'il était encodé en dehors des
valeurs des "character constant", que ce soit positif ou négatif,
on s'en moquerait, car celui qui fournir les isXXXX est aussi
celui qui décide le signe de char, donc il a juste a être cohérent
avec lui même.
6) si on manipule beaucoup de caractères accentués, on a avantage
quand c'est possible:
- soit à utiliser tout le temps unsigned char * à la place de char
*
Et les str* de string.h fonctionnent encore ?
Je note surtout le conseil des caractères accentué[s].
J'ai pas pour but de leur faire écrire une bibliothèque.
Mon cours commence avec:
- le C est un vieux langage (1970), moderne à l'époque...
En c12cg6$93g$, Marc Boyer va escriure:
Voilà, tu as compris.
Mon cours commence avec:
- le C est un vieux langage (1970), moderne à l'époque...
1972. Si tu lis l'anglais, la référence est à
<URL:http://cm.bell-labs.com/cm/cs/who/dmr/primevalC.html>
En c12cg6$93g$1@news.cict.fr, Marc Boyer va escriure:
Voilà, tu as compris.
Mon cours commence avec:
- le C est un vieux langage (1970), moderne à l'époque...
1972. Si tu lis l'anglais, la référence est à
<URL:http://cm.bell-labs.com/cm/cs/who/dmr/primevalC.html>
En c12cg6$93g$, Marc Boyer va escriure:
Voilà, tu as compris.
Mon cours commence avec:
- le C est un vieux langage (1970), moderne à l'époque...
1972. Si tu lis l'anglais, la référence est à
<URL:http://cm.bell-labs.com/cm/cs/who/dmr/primevalC.html>
Antoine Leca wrote:En c12cg6$93g$, Marc Boyer va escriure:
Voilà, tu as compris.
Je garde juste cette citation, hors contexte,
par pur plaisir ;-)Mon cours commence avec:
- le C est un vieux langage (1970), moderne à l'époque...
1972. Si tu lis l'anglais, la référence est à
<URL:http://cm.bell-labs.com/cm/cs/who/dmr/primevalC.html>
Voui.
Bon, sinon, tu ne m'as pas repris sur ce que j'allais
leur raconter (stockage dans des char et test par feof et
ferror + transtypage pour les isXXX), j'en déduis que
c'est correct.
Antoine Leca wrote:
En c12cg6$93g$1@news.cict.fr, Marc Boyer va escriure:
Voilà, tu as compris.
Je garde juste cette citation, hors contexte,
par pur plaisir ;-)
Mon cours commence avec:
- le C est un vieux langage (1970), moderne à l'époque...
1972. Si tu lis l'anglais, la référence est à
<URL:http://cm.bell-labs.com/cm/cs/who/dmr/primevalC.html>
Voui.
Bon, sinon, tu ne m'as pas repris sur ce que j'allais
leur raconter (stockage dans des char et test par feof et
ferror + transtypage pour les isXXX), j'en déduis que
c'est correct.
Antoine Leca wrote:En c12cg6$93g$, Marc Boyer va escriure:
Voilà, tu as compris.
Je garde juste cette citation, hors contexte,
par pur plaisir ;-)Mon cours commence avec:
- le C est un vieux langage (1970), moderne à l'époque...
1972. Si tu lis l'anglais, la référence est à
<URL:http://cm.bell-labs.com/cm/cs/who/dmr/primevalC.html>
Voui.
Bon, sinon, tu ne m'as pas repris sur ce que j'allais
leur raconter (stockage dans des char et test par feof et
ferror + transtypage pour les isXXX), j'en déduis que
c'est correct.
Marc Boyer writes:Bon, sinon, tu ne m'as pas repris sur ce que j'allais
leur raconter (stockage dans des char et test par feof et
ferror + transtypage pour les isXXX), j'en déduis que
c'est correct.
Il y a un probleme si une erreur de lecture a lieu, sinon si je
comprends bien la norme feof() n'est vrai apres un fgetc)_ que si la
lecture a echoue. Note que ce n'est pas le cas en general pour les
autres fonctions de lecture apres lesquelles feof() peut etre vrai
alors que la lecture a reussi (mais la suivante echouera). Ce qui est
vraissemblablement la raison fondamentale pour laquelle on n'utilise
pas cette structure.
Marc Boyer <Marc.Boyer@enseeiht.yahoo.fr.invalid> writes:
Bon, sinon, tu ne m'as pas repris sur ce que j'allais
leur raconter (stockage dans des char et test par feof et
ferror + transtypage pour les isXXX), j'en déduis que
c'est correct.
Il y a un probleme si une erreur de lecture a lieu, sinon si je
comprends bien la norme feof() n'est vrai apres un fgetc)_ que si la
lecture a echoue. Note que ce n'est pas le cas en general pour les
autres fonctions de lecture apres lesquelles feof() peut etre vrai
alors que la lecture a reussi (mais la suivante echouera). Ce qui est
vraissemblablement la raison fondamentale pour laquelle on n'utilise
pas cette structure.
Marc Boyer writes:Bon, sinon, tu ne m'as pas repris sur ce que j'allais
leur raconter (stockage dans des char et test par feof et
ferror + transtypage pour les isXXX), j'en déduis que
c'est correct.
Il y a un probleme si une erreur de lecture a lieu, sinon si je
comprends bien la norme feof() n'est vrai apres un fgetc)_ que si la
lecture a echoue. Note que ce n'est pas le cas en general pour les
autres fonctions de lecture apres lesquelles feof() peut etre vrai
alors que la lecture a reussi (mais la suivante echouera). Ce qui est
vraissemblablement la raison fondamentale pour laquelle on n'utilise
pas cette structure.
Jean-Marc Bourguet wrote:Marc Boyer writes:Bon, sinon, tu ne m'as pas repris sur ce que j'allais
leur raconter (stockage dans des char et test par feof et
ferror + transtypage pour les isXXX), j'en déduis que
c'est correct.
Il y a un probleme si une erreur de lecture a lieu, sinon si je
comprends bien la norme feof() n'est vrai apres un fgetc)_ que si la
lecture a echoue. Note que ce n'est pas le cas en general pour les
autres fonctions de lecture apres lesquelles feof() peut etre vrai
alors que la lecture a reussi (mais la suivante echouera). Ce qui est
vraissemblablement la raison fondamentale pour laquelle on n'utilise
pas cette structure.
Je suis pas sur de te suivre.
Il me semble que l'idiome des E/S en C, c'est qu'il
faut échouer dans une lecture pour s'appercevoir qu'on
est à la fin, et dans ce cadre, je ne vois pas la distinction
entre getc[har] et fgets par exemple.
J'ai raté un truc ?
char c;
if ( (c=getc()) && !feof )
en lieu et place de
int c;
if ( (c=getc()) != EOF )
mais le jour ou on a du y penser, il devait être trop tard.
Jean-Marc Bourguet wrote:
Marc Boyer <Marc.Boyer@enseeiht.yahoo.fr.invalid> writes:
Bon, sinon, tu ne m'as pas repris sur ce que j'allais
leur raconter (stockage dans des char et test par feof et
ferror + transtypage pour les isXXX), j'en déduis que
c'est correct.
Il y a un probleme si une erreur de lecture a lieu, sinon si je
comprends bien la norme feof() n'est vrai apres un fgetc)_ que si la
lecture a echoue. Note que ce n'est pas le cas en general pour les
autres fonctions de lecture apres lesquelles feof() peut etre vrai
alors que la lecture a reussi (mais la suivante echouera). Ce qui est
vraissemblablement la raison fondamentale pour laquelle on n'utilise
pas cette structure.
Je suis pas sur de te suivre.
Il me semble que l'idiome des E/S en C, c'est qu'il
faut échouer dans une lecture pour s'appercevoir qu'on
est à la fin, et dans ce cadre, je ne vois pas la distinction
entre getc[har] et fgets par exemple.
J'ai raté un truc ?
char c;
if ( (c=getc()) && !feof )
en lieu et place de
int c;
if ( (c=getc()) != EOF )
mais le jour ou on a du y penser, il devait être trop tard.
Jean-Marc Bourguet wrote:Marc Boyer writes:Bon, sinon, tu ne m'as pas repris sur ce que j'allais
leur raconter (stockage dans des char et test par feof et
ferror + transtypage pour les isXXX), j'en déduis que
c'est correct.
Il y a un probleme si une erreur de lecture a lieu, sinon si je
comprends bien la norme feof() n'est vrai apres un fgetc)_ que si la
lecture a echoue. Note que ce n'est pas le cas en general pour les
autres fonctions de lecture apres lesquelles feof() peut etre vrai
alors que la lecture a reussi (mais la suivante echouera). Ce qui est
vraissemblablement la raison fondamentale pour laquelle on n'utilise
pas cette structure.
Je suis pas sur de te suivre.
Il me semble que l'idiome des E/S en C, c'est qu'il
faut échouer dans une lecture pour s'appercevoir qu'on
est à la fin, et dans ce cadre, je ne vois pas la distinction
entre getc[har] et fgets par exemple.
J'ai raté un truc ?
char c;
if ( (c=getc()) && !feof )
en lieu et place de
int c;
if ( (c=getc()) != EOF )
mais le jour ou on a du y penser, il devait être trop tard.