getchar ne get pas du tout un char [info C] - C++ - Programmation
Marsh Posté le 21-11-2002 à 17:47:31
g une tite question sur le niveau2 : char c = getchar()
si getchar retourne EOF, quelle valeur va prendre c ? ou p-e cela va-t-il faire une erreur ?
je lis la suite ...
c super interressant je trouve comme sujet, les trucs ou tlm passe dessus sans faire attention mais il y a tellement de choses a dire dessus, j'adore ces questions "bas niveau"
Marsh Posté le 21-11-2002 à 17:48:41
oups j'aurais p-e du lire la suite ... je reposerais ma question a la fin si elle a tjs lieu ... en tt cas super sujet
Marsh Posté le 21-11-2002 à 17:51:56
si, ma question reste alors ...
Marsh Posté le 21-11-2002 à 18:02:42
(dsl, g ecrit juste ce message pour etre notifier par mail)
(je savais pas comment faire en editant)
Marsh Posté le 21-11-2002 à 18:22:28
BlackGoddess a écrit a écrit : (dsl, g ecrit juste ce message pour etre notifier par mail) (je savais pas comment faire en editant) |
Il te suffit de cliquer là :
http://forum.hardware.fr/email.php [...] ic=&theme=
Marsh Posté le 21-11-2002 à 20:55:35
Je vois pas où est le probleme si on a bien compris que les valeures signées c pas des valeures non signées
Marsh Posté le 22-11-2002 à 00:44:43
Je pensais pas qu'il remonterait celui-là...
BlackGoddess a écrit a écrit : g une tite question sur le niveau2 : char c = getchar() si getchar retourne EOF, quelle valeur va prendre c ? ou p-e cela va-t-il faire une erreur ? |
Si char est non-signé, il subit un modulo CHAR_MAX+1.
Cela ferait probablement -1%256= 255 dans ce contexte.
Si char est signé, c'est dépendant... Le plus simple, c'est de conserver la même représentation de bits.
En complément à deux sur 8 bits, cela transforme -1 en 255.
Cela ne déclenchera pas d'erreur d'après le standard.
Il faut se souvenir de ces histoires de calculs sur types différents.
Comme c'est assez courant, les compilateurs ne sont pas bien bavards là-dessus, et les erreurs de portabilité sont faciles à faire.
Marsh Posté le 22-11-2002 à 16:25:38
et les erreurs de portabilité sont faciles à faire.
bin une erreur c tjs facile a faire lol
Marsh Posté le 22-11-2002 à 23:21:35
Ouais d'accord...
J'aurais dû dire qu'elles sont pas faciles à trouver.
Ça te vas ?
Marsh Posté le 23-11-2002 à 21:37:23
hey jme moquais pas !!! c t ironique j'avais tres bien compris !
Marsh Posté le 24-11-2002 à 03:03:50
Mais non, c'est vrai !
Cette mauvaise formulation trahit une pensée confuse, pas assez bien formée et mal maitrisée.
Et même fausse: certains se donnent beaucoup de mal pour exploiter ces opportunités de bogues.
La vérité est qu'elles sont difficiles à repérer puisqu'il faut changer de plate-forme pour qu'elles surgissent (peut-être).
C'est d'ailleurs un test recommandé.
Faut pas chercher la petite bête avec moi...
Marsh Posté le 24-11-2002 à 04:05:46
Musaran a écrit a écrit : Mais non, c'est vrai ! Cette mauvaise formulation trahit une pensée confuse, pas assez bien formée et mal maitrisée. Et même fausse: certains se donnent beaucoup de mal pour exploiter ces opportunités de bogues. La vérité est qu'elles sont difficiles à repérer puisqu'il faut changer de plate-forme pour qu'elles surgissent (peut-être). C'est d'ailleurs un test recommandé. Faut pas chercher la petite bête avec moi... |
Maintenant on sait qu'il a une petite b...ête.
A+,
Marsh Posté le 14-10-2002 à 03:34:26
Aïe aïe aïe...
J'ai voulu savoir comment il fallait vraiment manipuler getchar, et une maison m'est tombée sur la tête !
Tout ce qui suit s'applique à:
Niveau 1
Il suffit de lire la documentation pour remarquer que le type de retour est int, et non pas char.
La raison est historique: à l'époque de ces fonctions antédilluviennes, toutes les fonctions renvoyaient le seul type existant: int.
Les types plus petits qu'un int étant promus en int pour la transmission, il n'y avait pas grand mal.
Et puis cela permettait de signaler les erreurs...
Niveau 2
Puisqu'un int dispose de plus de valeurs qu'un char, on en a profité pour spécifier une valeur de retour spéciale:
EOF, qui indique qu'une erreur est survenue, ou que la fin de l'entrée est atteinte.
Ce n'est pas un caractère, sa valeur n'est celle d'aucun caractère.
Une conséquence directe est que ceci est bogué:
En effet, on compare à EOF non pas la valeur renvoyée par getchar, mais la valeur contenue dans c après affectation.
EOF n'étant pas représentable dans un char, ce code ne marche pas. Du moins ne devrait pas, certains compilateurs le faisant fonctionner à tort.
La solution est simple: c doit être un int.
Malheureusement, il y a pire...
Niveau 3
Le standard spécifie que le type char est distinct de signed char et unsigned char, et que chaque implémentation(1) est libre de le faire se comporter comme l'un ou l'autre. C'est pour leur permettre de choisir ce qui se manipule le mieux, et qui est le plus rapide.
Seulement, getchar & co. renvoient un code de caractère toujours positif, assimilable à un unsigned char. Probablement une raison historique...
Une conséquence directe est que ceci est bogué (bis):
Si char est non-signé, aucun problème.
Si char est signé, alors quoi ?
L'affectation est orientée sur la valeur arithmétique, et la préserve quand c'est possible.
Les règles exactes sont:
Si la valeur source peut être représentée dans le type de destination, elle est inaltérée.
Autrement, si le type de destination est non-signé, la valeur est réduite via modulo U<type>_MAX+1.
Autrement le type de destination est signé et la valeur est dépendante de l'implémentation.
Donc, si la valeur renvoyéee par getchar est trop grande, le résultat est dépendant... Il peut même y avoir un signal de levé.
Dans la plupart des cas, les bits sont simplement copiés, mais ça n'est absolument pas garanti.
En particulier, il peut ne pas y avoir une correspondance réversible entre valeurs des version signed et unsigned d'un type:
Votre documentation est censée mentionner quelque part quelle transformation est effectuée. Sincèrement, je doute qu'elle le fasse.
C'est bien beau tout ça, mais alors on fait comment ?
Niveau 4
Ce qui est toujours bogué (ter):
Stupides:
c1: L'int intermédiaire ne fait que retarder le problème.
c2: Le cast en char a de toutes façons lieu à l'affectation, c'est lui qui transforme la valeur.
c3: Pas mal.
Ça donne bien une valeur dans toute la gamme d'un char. C'est même optimisé si char est non-signé.
Mais... ce n'est pas forcément la valeur attendue par putchar, celle qui afficherait le caractère qui a été entré.
c4: Bien essayé...
Malheureusement, le codet(2) récupéré dépend du boutisme(3), ce n'est pas forcément celui qui nous intéresse.
Niveau 5
Ce qui devrait marcher:
Et encore... Les conversions entre pointeurs de types différents ne sont pas garanties de marcher (sauf void*). Je ne sais pas si ça concerne même les variantes de signes...
EOF ne convient pas comme valeur de retour, car bien que ce ne soit pas une valeur de unsigned char, ça pourrait être valeur de char signé. D'ailleurs, ç'est très souvent -1.
Conclusion
Ça fait peur, non ?
En fait, il y a très peu de chances que tout ceci ai une quelconque importance pour vous.
On imagine mal un compilateur foirer un truc aussi simple que la lecture de caractères.
Mais, telle une épée de Damoclès, ça peut vous tomber dessus un jour.
A noter que les formats "%c" et "%s" de scanf et fscanf ne doivent logiquement pas souffrir de ce problème.
En effet, ils ignorent le type du pointeur reçu, à cause de la liste d'argument variable, et écrivent une représentation binaire sans même pouvoir se soucier de valeur arithmétique.
Cas du C++
(1)implémentation:
Quasiment synonyme de compilateur.
(2)codet:
Mot français pour byte.
L'octet fait spécifiquement 8 bits, ce qui n'est pas toujours le cas du byte.
Le char du C++ défini comme un byte.
Donc, codet. Ou multiplet.
(3)boutisme:
Mot français pour endianness.
L'ordre dans lequel les octets d'une valeur sont placés en mémoire.
Autrement dit: par quel bout commence-t'on ?
Il existe aussi un boutisme pour l'ordre des bits.
Voilà, la visite guidée est terminée, je vous remercie de m'avoir suivi dans les tréfonds de la machinerie du C.
Message édité par Musaran le 14-10-2002 à 23:24:02
---------------
Bricocheap: Montage de ventilo sur paté de mastic silicone