Stockage du caractère EOF (End of File) dans un type de caractère
On février 18, 2021 by admin Jai lu dans le langage de programmation C de Dennis Ritchie livre que int
doit être utilisé pour quune variable contienne EOF – pour la rendre suffisamment grande pour quelle puisse contenir la valeur EOF – pas char
. Mais le code suivant fonctionne très bien:
#include<stdio.h> main() { char c; c=getchar(); while(c!=EOF) { putchar(c); c=getchar(); } }
Quand il y a nest plus une entrée, getchar
renvoie EOF. Et dans le programme ci-dessus, la variable c
, de type char, est capable de la contenir avec succès.
Pourquoi cela fonctionne-t-il? Comme expliqué dans le livre ci-dessus, le code ne devrait pas fonctionner.
Commentaires
Answer
Votre code semble fonctionner, car les conversions de types implicites se produisent accidentellement pour faire la bonne chose.
getchar()
renvoie un int
avec une valeur qui correspond à la plage de unsigned char
ou est EOF
( qui doit être négatif, généralement -1). Notez que EOF
lui-même nest pas un caractère, mais un signal quil ny a plus de caractères disponibles.
Lors du stockage du résultat de getchar()
dans c
, il y a deux possibilités. Soit le type char
peut représenter la valeur, auquel cas cest la valeur de c
. Ou le type char
ne peut pas représenter la valeur. Dans ce cas, ce qui va se passer nest pas défini. Les processeurs Intel coupent simplement les bits hauts qui ne correspondent pas au nouveau type (réduisant effectivement la valeur modulo 256 pour char
), mais vous ne devriez pas vous y fier.
Létape suivante consiste à comparer c
avec EOF
. Comme EOF
est un int
, c
sera également converti en int
, en préservant la valeur stockée dans c
. Si c
pouvait stocker la valeur de EOF
, alors la comparaison réussira , mais si c
ne pouvait pas stocker la valeur, alors la comparaison échouera, car il y a eu une perte irrécupérable dinformations lors de la conversion de EOF
pour taper char
.
Il semble que votre compilateur ait choisi de créer le type char
signé et la valeur de EOF
petite assez pour tenir dans char
. Si char
nétait pas signé (ou si vous aviez utilisé unsigned char
), votre test aurait échoué, car unsigned char
ne peut « t contenir la valeur de EOF
.
Notez également quil y a un deuxième problème avec votre code. Comme EOF
nest pas un caractère lui-même, mais vous le forcez dans un type char
, il y a très probablement un caractère là-bas qui est mal interprété comme étant EOF
et pour la moitié des caractères possibles, il est indéfini sils seront traités correctement.
Commentaires
- Coercition pour saisir des valeurs de
char
en dehors de la plageCHAR_MIN
..CHAR_MAX
sera nécessaire pour donner soit une valeur définie par limplémentation, renvoie un modèle de bits que limplémentation définit comme une représentation dinterruption ou déclenche un signal défini par limplémentation. Dans la plupart des cas, les implémentations doivent faire beaucoup de travail supplémentaire pour faire autre chose que deux ' réduction du complément s.Si les membres du Comité des normes souscrivaient à lidée que les compilateurs devraient être encouragés à mettre en œuvre des comportements cohérents avec celui de la plupart des autres compilateurs en labsence de raisons de faire autrement … - … la coercition comme étant fiable (pour ne pas dire que le code ne devrait pas ' t documenter ses intentions, mais que
(signed char)x
devrait être considéré comme plus clair et tout aussi sûr comme((unsigned char)x ^ CHAR_MAX+1))-(CHAR_MAX+1)
.) En létat, je ne vois ' aucune probabilité que les compilateurs implémentent tout autre comportement conforme à aujourdhui '; le seul danger serait que la norme puisse être modifiée pour briser le comportement dans lintérêt supposé de " optimisation ". - @supercat: Le standard est écrit de telle sorte quaucun compilateur nait à produire du code dont le comportement nest pas naturellement pris en charge par le processeur quil cible. La plupart des comportements non définis sont présents car (au moment de la rédaction de la norme) tous les processeurs ne se comportaient pas de manière cohérente. Les compilateurs devenant plus matures, les rédacteurs de compilateurs ont commencé à profiter du comportement non défini pour faire des optimisations plus agressives.
- Historiquement, lintention du Standard était principalement celle que vous décrivez, bien que le Standard décrit certains comportements dans suffisamment de détails pour exiger que les compilateurs de certaines plates-formes courantes génèrent plus de code que ce qui serait requis dans une spécification plus souple. La contrainte de type dans
int i=129; signed char c=i;
est lun de ces comportements. Relativement peu de processeurs ont une instruction qui rendraitc
égali
quand il ' la plage de -127 à +127 et donnerait tout mappage cohérent des autres valeurs dei
aux valeurs de la plage de -128 à +127 qui différaient de deux ' réduction du complément s, ou … - … augmenterait systématiquement un signal dans de tels cas. Étant donné que la norme exige que les implémentations produisent un mappage cohérent ou augmentent systématiquement un signal, les seules plates-formes où la norme laisserait de la place pour autre chose que deux ' réduction du complément s seraient des choses comme les DSP avec du matériel arithmétique saturant. En ce qui concerne la base historique du comportement indéfini, je dirais que le problème ' nest pas uniquement lié aux plates-formes matérielles. Même sur une plate-forme où le débordement se comporterait de manière très cohérente, il peut être utile davoir un compilateur le piéger …
0xff
. Stockage du résultat degetchar()
dans unint
résout ce problème. Votre question est essentiellement la même que la question 12.1 de la FAQ comp.lang.c , qui est une excellente ressource. (De plus,main()
devrait êtreint main(void)
, et cela ne ferait pas ' dajouter unreturn 0;
avant la clôture}
.)