La comparaison de caractères avec des valeurs hexadécimales
Pour le dernier jour, j'ai eu un méchant bug dans mon code qui après quelques recherches, semble être liée à la comparaison entre le char des valeurs et de l'hex. Mon compilateur est gcc 4.4.1 en cours d'exécution sur Windows.
J'ai reproduit le problème dans le simple code ci-dessous:
char c1 = 0xFF; char c2 = 0xFE;
if(c1 == 0xFF && c2 == 0xFE)
{
//do something
}
Étonnamment le code ci-dessus ne fait pas dans la boucle. Je n'ai absolument aucune idée de pourquoi et voudrais vraiment l'apprécier un peu d'aide sur ce. C'est tellement absurde que la solution doit être (comme toujours) une énorme erreur de ma part que j'ai totalement négligé.
Si je remplace le dessus avec des caractères non signés cela fonctionne, mais seulement dans certains cas. J'ai du mal à savoir ce qu'il se passe. En plus si je jette les valeurs hexadécimales de char en comparaison, il entre dans la boucle correctement comme suit:
if(c1 == (char)0xFF && c2 == (char)0xFE)
{
//do something
}
Ça veut dire quoi? Pourquoi peut-il se passer? N'est-ce pas la brute valeur hex interprété comme un char par défaut?
Pour les curieux, le point dans mon code où j'ai d'abord remarqué c'est la comparaison des 2 premiers octets d'un ruisseau au-dessus de la valeur hex et leur reverse à l'identité de la Marque d'Ordre d'Octet.
Toute aide est appréciée
OriginalL'auteur Lefteris | 2012-01-13
Vous devez vous connecter pour publier un commentaire.
Plaine
char
peut êtresigned
ouunsigned
. Si le type estunsigned
, puis tout fonctionne comme vous le souhaitez.Si le type est
signed
, puis à attribuer 0xFF pourc1
signifie que la valeur sera promu à-1
lorsque la comparaison est exécuté, mais la 0xFF est régulièrement un entier positif, de sorte que la comparaison de-1 == 0xFF
échoue.Noter que les types
char
,signed char
etunsigned char
sont distincts, mais deux d'entre eux ont la même représentation (et l'un des deux estchar
).Vous avez quelques options. Vous pourriez lancer les valeurs hexadécimales à
(char)
, et le compilateur puis de les convertir de la même manière comme il convertit lechar
variable sur l'autre côté de la comparaison. Ou vous pouvez lancer lechar
variables à(unsigned char)
. Notez que la conversion à(unsigned)
serait mal avisé;-1
converti àunsigned
sur une machine avec 4 octetsint
serait de générer des 0xFFFFFFFF et pas 0xFF. Une autre option serait d'avoir un tableauchar charmap[256]
initialisé aveccharmap[i] = i;
, puis en comparantc1 == charmap[0xFE]
. Ou vous pouvez simplement utiliserunsigned char
.Je vois, merci pour votre réponse détaillée Jonathan. A été utile. De temps à fouiller dans mon code pour une telle comparaison et de le corriger avant qu'il revient à la mords-moi dans le cul plusieurs mois sur toute la ligne.
êtes-vous sûr que -1 (signé 0xFF) s'étend à 0xFFFFFFFF sur 4 octets de la machine quand il est converti en unsigned? Essayez
signed char x = 0xFF; printf("%08x\n", x); printf("%08x\n", (unsigned char)x);
. Je pense que @paxdiablo explique de la bonne façon dans son commentaire.Oui, j'en suis sûr. De plus, quand j'essaie votre fragment de code, j'obtiens deux lignes de sortie:
ffffffff
et000000ff
, qui est ce à quoi je m'attends. (Qu'attendez-vous? Que voyez-vous lorsque vous essayez?) Notez que l'argument deprintf()
est converti àint
(parce que toutes les variantes dechar
sont promus à laint
dans un appel à un variadic fonction commeprintf()
), puis interne àprintf()
, les formats d'indiquer que l'argument doit être traitée commeunsigned int
.OriginalL'auteur Jonathan Leffler
Le littéral
0xff
n'est pas unchar
, c'est unint
(signé). Lorsque vous chausse-pied dans unchar
variable, il fit ok, mais, selon que votrechar
type est signé ou non signé, cela va affecter la façon dont c'est mis à jour dans les expressions (voir ci-dessous).Dans une expression comme
if (c1 == 0xff)
, lec1
variable sera promu à un entier puisque c'est ce que0xff
est. Et ce qu'il est promu dépend s'il est signé ou non.Ligne de fond, vous pouvez faire une des deux choses.
Vous assurer que vous utilisez
signed char
de sorte qu'il "signe-s'étend" à la bonneint
. Je veux dire par là un unsigned char0xff
serait devenue (pour un 4 octetsint
)0x000000ff
(c'est donc toujours 255), mais un signé, on deviendrait0xffffffff
(c'est donc toujours -1).Chausse-pied le littéral dans le même type que la variable à laquelle vous êtes déjà en train de faire avec
(char)oxff
.en termes de code, nous avons vu méthode fonctionne très bien. Ce n'est pas à dire que vous n'avez pas certaines hypothèses ailleurs qui peuvent être affectés par votre choix. Personnellement, je préfère ma
char
des variables unsigned puis utiliser des constantes comme 255U (afin de s'assurer qu'ils correspondent à ce paramètre). Mais c'est six d'un et une demi-douzaine de l'autre.Merci. Malheureusement je n'ai pas pris cette erreur au début du projet, j'ai donc beaucoup de fixation pour le faire.
oui, vous l'avez. Bonne chance 🙂
OriginalL'auteur paxdiablo
Lors de la comparaison de char à hex, vous devez être prudent:
À l'aide de l'opérateur == pour comparer un char à 0x80 est toujours faux?
Je recommande cette syntaxe introduite en C99 pour être sûr
Éviter la fonte, c'est inutile et n'est pas sécurisé.
Il indique au compilateur que la 0xFF est un char plutôt qu'un int, cela permettra de résoudre votre problème.
clang compilateur va vous avertir de ce aussi:
comparaison de la constante 128 avec une expression de type 'char' est toujours faux [-Werror,-Wtautological-constant-de-gamme-comparez]
OriginalL'auteur ericcurtin
Le caractère 0xFE va-t-il traduit en un nombre entier négatif. Les constantes dans l'expression sera traduit en nombres entiers positifs.
char
et sichar
est un type signé, puis, lorsque la valeur assignée est promue à unint
pour la comparaison, alors...mais tout dépend de lachar
être signé, ce qui n'est pas automatiquement le cas (même si elle est, en effet, le cas de l'OP).OriginalL'auteur Ed Heal
Je l'ai résolu en associant mon variables à UINT16 (optimisé pour mon compilateur). Dans votre cas, vous serait casting c1 et c2 comme INT
OriginalL'auteur siggyt