Le langage de programmation C indique que les fonctions de ISO C99, 7.4P1: P> Dans tous les cas, l'argument est un Cela signifie que le code suivant est dangereux: p> si ce code est exécuté sur une implémentation où Je vois néanmoins beaucoup d'exemples en C ++ qui ne se soucient pas de cette possibilité de comportement non défini. Ainsi y a-t-il quelque chose dans la norme C ++ qui garantit que le code ci-dessus ne conduira pas à un comportement non défini, ou tous les exemples faux? P> [Mots-clés supplémentaires: CYPE CCTYPE Isalnum Isalpha Isblank Iscntrl Isdigit Islowwer isprint ispunct Isspace ispper isxdigit tolower] p> p>
int code>, la valeur qui doit être représentable en tant que
non signé Char code> ou doit être égal à la valeur de la macro
eof < / code>. Si l'argument a une autre valeur, le comportement est indéfini. P>
blockQuote>
Char code> a le Même espace de valeur que
signé caractère code> et il y a un caractère avec une valeur négative dans la chaîne, ce code invoque comportement non défini em>. La version correcte est la suivante: p>
3 Réponses :
Parfois, la plupart des gens ont tort. Je pense que c'est alors ici. Cela dit qu'il n'y a rien pour arrêter une implémentation de bibliothèque standard définissant le comportement que la plupart des gens attendent. Donc, peut-être que c'est pourquoi la plupart des gens ne se soucient pas, car ils n'ont jamais vu un bug résultant de cette erreur. P>
Comment sa version corrigée est-elle correcte? Casting La valeur négative au caractère non signé ne donnera rien de significatif!
Pourquoi pas? Si j'ai le personnage ä in Latin1 (ISO-8859-1), il est exprimé en tant que 228. Si mon caractère est signé, IST est stocké sous-28. Si je le jette pas non signé, ce sera à nouveau.
La valeur négative au caractère non signé est bien définie. La conversion originale d'un entier> = 128 pour signé de caractère est toutefois ub. Mais pas beaucoup de gens se soucient de cela. Néanmoins j'ai édité mon post.
@John: conversion de int code> à
Char code> n'est pas UB, il donne simplement une valeur définie sur la mise en oeuvre lorsque la valeur de la source n'est pas dans la plage représente en tant que
Char < / code>.
@John: Pourquoi avez-vous édité la dernière phrase de votre réponse d'origine? Y avait-il quelque chose de mal avec ça?
@Chals Bailey: Vous êtes correct bien sûr. Post modifié à nouveau. Ce genre de choses est très fastidieuse, tout le monde sait ce qui se produira réellement, il est dommage que la norme ne le garantit pas.
De Couse, toute implémentation dans laquelle la conversion d'un Char code> avec une valeur négative à un
non signé Char code> ne donne pas une valeur code> non signée de la valeur code> qui représente Le même caractère que l'original
Char code> est clairement écrou.
@glGL Si nous parlons en termes de programme de plateformes croisées, il est stocké uniquement sous-28 pour une représentation complémentaire TWO. Pour être portable, vous devez dire * (sans signé Char *) & s [index] code> de sorte que quelle que soit la valeur négative, que vous finissez par 228 sur la base de BitPattern.
Toute mise en oeuvre dans laquelle la plaine Char code> est signée et non twos-complément est absurde. Il existe de nombreux problèmes tels que "zéro négatif" existant, mais pas étant un terminateur à chaîne, et copier des octets comme une matrice de
char code> devenant une opération à perte. La spécification est plutôt floue sur ces questions. Il serait donc vraiment invité à faire une telle mise en œuvre.
@R. -Complément maths sans difficulté.
Pour ce que ça vaut, les compilateurs Solaris Studio (en utilisant me donne: p> pour référence: p> Edit: Comme il a été souligné que la version ci-dessus contenait un comportement non défini dans la tentative d'attribution de char ch = '\ xa1' code> en raison d'un débordement entier, voici une version qui évite et conserve toujours la même sortie: P> STLPORT4 CODE>) sont une de ces suites compilatrice qui produisent ici un résultat inattendu. Compiler et exécuter ceci:
kevin@solaris:~/scratch
$ CC whitespace.cpp && ./a.out
3
Char Code> a la mise en œuvre définie de la mise en œuvre. Si elle est signée et que vous stockez une valeur supérieure à 127, telle que 0xa1, vous invoquez un débordement entier, ce qui est un comportement indéfini. Ce bug UB arrive avant i> vous appelez la fonction CTYPE.H. Donc, cette réponse ne prouve rien, sauf qu'il est dangereux de déborder des entiers signés. Pas de nouvelles là-bas. Changer de caractère non signé et cela fonctionnera très bien.
Après la modification, lorsque vous avez défini -95 sur un caractère signé, celui-ci est converti en into lorsqu'il est passé à Isspace. Vous obtenez une conversion de lvalue de char code> sur
int code>. Le signe est préservé. Donc, ce que ce code passe à la fonction est 0xFFFFFFFA1. Cette valeur n'est pas représentative en tant que caractère non signé, ni en tant que EOF, le code invoque UB. Encore une fois, le problème ne ment pas avec les fonctions CTYPE.H, mais avec le programmeur à l'aide du type code> Char code> pour stocker des entiers. Pourquoi réussiriez-vous -95 aux fonctions CTYPE dans un programme mondial réel, je n'ai aucune idée. Si vous faites des choses vraiment étranges, les choses étranges se produiront.
L'OP ne demandait pas si c'était un comportement indéfini (nous le savons). L'OP demandait s'il existe une implémentation qui vous donne un résultat surprenant lorsque vous invoquez ce comportement non défini. Les compilateurs Solaris Studio se produisent une de ces suites compilatrice qui vous donnent des résultats surprenants, alors que j'imagine d'autres compilateurs ( gcc code>,
clang code>) fait probablement la bonne chose et vous donner un résultat sain même s'il est ub.
@LUNDIN stockage des valeurs arbitraires dans un char code> objet pas i> Invoque un comportement non défini, voir 6.2.5p3 dans N1570.PDF.
@Rolandillig J'ai déjà répondu à cela dans un commentaire précédent. Vous ne pouvez pas stocker les valeurs qui ne correspondent pas, période.
Ah, dans le cas spécifique de la conversion d'affectation / Lvalue, il n'est pas nécessairement ub mais implanté comportement défini. La partie correspondante serait 6.3.1.3/3 "sinon, le nouveau type est signé et la valeur ne peut être représentée; soit le résultat est défini par la mise en œuvre ou un signal défini par la mise en œuvre est soulevé." Peu importe, ne le faites pas.
L'historique derrière le type code> Char code> est qu'il était à l'origine le type utilisé pour décrire les caractères ASCII 7 bits. Dans le même temps, c Manque de type integer 8 bits séparé. Donc, dans les jours de pré-standard des années quatre-vingt, certains compilateurs fabriqués Quand le temps est venu de normaliser c, les deux versions existaient. Malheureusement, le Comité a décidé de le laisser rester de cette façon, laissant la décision au compilateur. Au lieu de cela, ils ont ajouté deux autres types: notamment, maintenant si Les fonctions CTYPE.H Autoriser Mais si vous passez un Un exemple de comportement non défini causé par les restrictions CITE CITE.H dans 7.4 serait plutôt quelque chose comme sans signé - car il n'a pas de sens d'avoir des indices négatifs dans une table de symboles, tandis que d'autres compilateurs ont fait
char Code> Signé, pour le rendre cohérent avec tous les autres types entier. P>
signé Char code> et
non signé Char code>.
SIGNÉ CHAR CODE> fait partie des types d'entiers signés,
Unsigned Char CODE> fait partie des types d'entiers non signés et
Char code> fait partie de l'un ni l'autre Doit avoir la même représentation que l'un ou l'autre
signé caractère code> ou
non signé Char code>. (Ceci est tout décrit dans C11 6.2.5) P>
Char code> n'a jamais été quelque chose que 8 bits sur toutes les implémentations connues, économisez de certains DSP de boules d'odeur exotiques qui fonctionnaient avec 16 bitts. Lorsque des tables de symboles "étendues" ont été utilisées, la mise en œuvre est passée de 7 à 8 caractères bits, soit
wchar_t code> a été utilisé. Veuillez noter que
wchar_t code> est dans la langue C depuis le début, supposant ainsi que
Char code> était à un moment donné pour des éléments tels que UTF8 est probablement incorrect (bien possible théoriquement). p>
Char code> est signé et que vous stockez une valeur supérieure à
char_max code> ou plus petit que
char_min code> à l'intérieur, vous invoquez un comportement non défini, conformément au C11 6.5 §5. Point final. Donc, si vous avez un tableau de
Char code> et n'importe quel article à l'intérieur, il enfreint les limites de type, vous avez déjà un comportement indéfini là-bas. Même si les types de caractères doivent piéger des représentations, un comportement indéfini pourrait entraîner une mauvaise conduite du code d'une autre manière, telles que des optimisations incorrectes. P>
EOF code> comme paramètre, mais autrement se comporter comme si vous travaillez avec des types de caractères, même si le paramètre est
int code> pour autoriser
eof code>. Le texte du 7.4 §1 dit principalement que "si vous passez du hasard
int code> à cette fonction, qui n'est ni de la même représentation qu'un caractère, ni EOF, le comportement n'est pas défini" strong>. p>
char code> où vous avez déjà invoqué SIGNÉ ENTREGER Overflow / Integer, vous avez déjà un comportement non défini avant d'appeler la fonction - cela n'a rien à voir avec les fonctions CTYPE.H ou toute autre fonction. Ainsi, votre hypothèse que la fonction postée "supérieure" est dangereuse est incorrecte - ce code n'est pas différent de tout autre code à l'aide du type code> char code>. p>
Toupper (666) Code>. P>.
C11 6.2.5P3 semble permettre de sauvegarder des "caractères" arbitraires dans un objet de type de caractère, qui contredire le comportement non défini de 6.5P5.
Dans votre devis de 7.4p1, il devrait être "non signé de caractère" au lieu de "caractère". Sur une plate-forme où char_bit code> est 8 et
Char code> est signé, appelant
TUPPER (192) code> n'appuie pas un comportement non défini. (Votre devis suggère le contraire.)
@Rolandillig No, 6.2.5p3 Points sur le jeu de caractères d'exécution de base I> qui est un terme formel défini dans 5.2.1. Signifiant à peu près l'alphabet anglais en majuscules et minuscules, plus des chiffres et des caractères de ponctuation, etc., ce qui signifie à son tour 7 bits ASCII - à tout prix, le jeu de caractères d'exécution de base peut correspondre à 7 bits. Au-delà de cela, il est indiqué que d'autres caractères peuvent être stockés de manière définie par la mise en œuvre " mais doivent figurer dans la plage de valeurs pouvant être représentées dans ce type b>". Ce qui signifie que vous n'êtes toujours pas autorisé à débordement / débordement.
@Rolandillig concernant 7.4, je ne l'ai pas cité. Oui, Toupper (192) Code> va bien, je n'ai pas dit autrement. Mais
CHAR CH = 192; CODE> est un comportement potentiellement indéfini, peu importe si vous passez le caractère à une fonction ou non. L'ensemble de cette réponse consiste à souligner qu'il n'y a que deux problèmes ici: 1) Overflowing / Endfloquant un char ou tout autre entiers signé est UB. 2) Transmettre une valeur orale aléatoire sur les fonctions CTYPE.H est UB. Le code de votre question n'est-il pas non plus, il est donc parfaitement parfait et sûr.
Dans votre réponse, vous avez écrit: "Maintenant si Char code> est signé et que vous stockez une valeur plus grande que
char_max code> ou plus petit que
char_min code> à l'intérieur, Vous invoquez un comportement non défini, conformément au C11 6.5 §5. Période. " - Je suis en désaccord avec cette déclaration. La partie pertinente de la norme dans ce cas est §6.3.1.3 ¶3 , qui indique que le résultat est défini par la mise en oeuvre ou un signal défini par la mise en œuvre est soulevé. Dans votre commentaire à l'une des autres réponses, vous l'avez signalé vous-même, mais il semble que vous ne mettez pas à jour votre propre réponse par la suite.
@Andreaswenzel La partie que vous citez s'applique lorsque les conversions ont lieu. Mais vous pouvez stocker une valeur dans une variable sans appeler des conversions. Par exemple, à travers l'accès LValue: * (sans signé Char *) pointer_to_char = char_max + 1; code>. Ceci est par exemple ce qui se passe si vous écrivez le mauvais spécificateur de conversion sur
scanf code>.
Vous demandez à propos de C ++ mais citant de C99?
Oh bien, C ++ 98 était avant C99. Néanmoins, le texte de C90 est presque identique, et C ++ 98 emprunte sa bibliothèque standard de C90, donc oui, je tiens à la norme C intentionnellement.
La signature de Char est spécifique au compilateur. Bien que j'en doute, peut-être que certains de ces "faux" exemples de projets forcent le compilateur à traiter des caractères non signés.
@CNICUTAR La norme C ++ 98 contient des détails sur. Suite aux normes C ++ ont supprimé la section entièrement en faveur de l'indiquant explicitement [cctype.syn] b> que l'on devrait se référer à la section 7.4 ISO C pour les définitions, dans laquelle l'ISO C est la dernière norme C au moment de la rédaction de la rédaction. (c.-à-d. C99 dans tous les cas). La citation de l'OP est donc la citation correcte (et uniquement), selon toutes les normes C ++ au cours des 20 dernières années. C'était également le cas il y a 10 ans lorsque l'OP a été posté. :)