En C/C++, à quoi sert un unsigned char
? En quoi est-il différent d'un char
normal?
En C++, il existe trois types de caractère distincts :
char
signed char
_unsigned char
_Si vous utilisez des types de caractères pour le texte , utilisez l'option char
non qualifiée:
'a'
_ ou _'0'
_."abcde"
_Cela fonctionne également comme une valeur numérique, mais il n'est pas spécifié si cette valeur est traitée comme signée ou non signée. Méfiez-vous des comparaisons de caractères par le biais d'inégalités - bien que si vous vous limitez à ASCII (0-127), vous êtes sur le point de ne pas risque.
Si vous utilisez des types de caractères sous forme de nombres , utilisez:
signed char
_, qui vous donne au moins la plage de -127 à 127. (-128 à 127 est commun)unsigned char
_, qui vous donne au moins la plage de 0 à 255."Au moins", car la norme C++ ne donne que la plage minimale de valeurs que chaque type numérique doit couvrir. sizeof (char)
doit être égal à 1 (c'est-à-dire un octet), mais un octet pourrait théoriquement être par exemple 32 bits. sizeof
RAPPORTERA TOUJOURS SA TAILLE SOUS LA FORME _1
- ce qui signifie que vous pourriez avoir sizeof (char) == sizeof (long) == 1
.
Cela dépend de la mise en œuvre, car le standard C NE définit PAS la signature de char
. Selon la plate-forme, char peut être signed
ou unsigned
, vous devez donc demander explicitement signed char
ou unsigned char
si votre implémentation en dépend. Utilisez simplement char
si vous souhaitez représenter des caractères à partir de chaînes, car cela correspond à ce que votre plate-forme place dans la chaîne.
La différence entre signed char
et unsigned char
est conforme à vos attentes. Sur la plupart des plates-formes, signed char
sera un numéro de complément à 8 bits allant de -128
à 127
, et unsigned char
sera un entier non signé de 8 bits (0
à 255
). Notez que la norme n'exige PAS que les types char
aient 8 bits, uniquement que sizeof(char)
renvoie 1
. Vous pouvez obtenir le nombre de bits d'un caractère avec CHAR_BIT
dans limits.h
. Cependant, il existe peu ou pas de plates-formes où ce sera autre chose que 8
.
Il existe un bon résumé de ce problème ici .
Comme d'autres l'ont mentionné depuis que j'ai posté ceci, vous feriez mieux d'utiliser int8_t
et uint8_t
si vous voulez vraiment représenter de petits entiers.
Parce que j'estime que c'est vraiment nécessaire, je veux juste énoncer quelques règles de C et C++ (elles sont les mêmes à cet égard). Tout d'abord, tous les bits sur unsigned char
participe à la détermination de la valeur, le cas échéant, de l'objet char non signé. Deuxièmement, unsigned char
est explicitement déclaré non signé.
Maintenant, j'ai discuté avec quelqu'un de ce qui se passe lorsque vous convertissez la valeur -1
de type int en unsigned char
. Il a refusé l'idée que tous les bits du unsigned char
résultant soient définis sur 1, car il craignait la représentation des signes. Mais il n'est pas obligé. En suivant immédiatement cette règle, la conversion fait ce qui est prévu:
Si le nouveau type n'est pas signé, la valeur est convertie en ajoutant ou en soustrayant de manière répétée une valeur de plus que la valeur maximale pouvant être représentée dans le nouveau type jusqu'à ce que la valeur se situe dans la plage du nouveau type. (
6.3.1.3p2
dans un brouillon C99)
C'est une description mathématique. C++ le décrit en termes de modulo calcul, qui obéit à la même règle. Quoi qu'il en soit, ce qui est non garanti, c'est que tous les bits du nombre entier -1
sont égaux à un avant la conversion. Alors, qu'est-ce que nous avons pour pouvoir prétendre que le unsigned char
résultant a tous ses CHAR_BIT
bits devenus 1?
UCHAR_MAX+1
à -1
donnera une valeur dans la plage, à savoir UCHAR_MAX
C'est assez, en fait! Donc, chaque fois que vous voulez avoir un unsigned char
ayant tous ses bits un, vous faites
unsigned char c = (unsigned char)-1;
Il s'ensuit également qu'une conversion ne fait que pas simplement tronquer les bits de poids fort. L'événement chanceux pour complément à deux est qu'il ne s'agit que d'une troncature, mais que ce n'est pas nécessairement le cas pour les autres représentations de signe.
Comme par exemple les utilisations de nsigned char:
nsigned char est souvent utilisé en infographie, qui attribue très souvent (mais pas toujours) un octet à chaque composant couleur. Il est courant de voir une couleur RVB (ou RVBA) représentée par 24 (ou 32) bits, chacun un caractère non signé. Puisque les valeurs nsigned char se situent dans la plage [0,255], elles sont généralement interprétées comme suit:
Ainsi, vous obtiendrez un rouge RVB tel que (255,0,0) -> (100% rouge, 0% vert, 0% bleu).
Pourquoi ne pas utiliser un caractère signé? L'arithmétique et le transfert de bits deviennent problématiques. Comme expliqué précédemment, la plage de signée est essentiellement décalée de -128. Une méthode très simple et naïve (la plupart du temps inutilisée) pour convertir RVB en niveaux de gris consiste à faire la moyenne des trois composantes de couleur, mais cela peut poser problème lorsque les valeurs des composantes de couleur sont négatives. Le rouge (255, 0, 0) fait la moyenne de (85, 85, 85) lorsque caractère non signé arithmétique. Cependant, si les valeurs étaient caractère signé s (127, -128, -128), nous nous retrouverions avec (-99, -99, -99), ce qui serait (29, 29, 29) dans notre nsigned char space, ce qui est incorrect.
Si vous souhaitez utiliser un caractère sous forme de petit nombre entier, le moyen le plus sûr consiste à utiliser les types int8_t
et uint8_t
.
unsigned char
ne prend que des valeurs positives .... comme à 255
tandis que
signed char
prend les valeurs positives et négatives .... comme - 128 à + 127
char
et unsigned char
ne sont pas garantis en tant que types 8 bits sur toutes les plates-formes; ils sont garantis au moins en 8 bits. Certaines plates-formes ont octets 9 bits, 32 bits ou 64 bits . Cependant, les plates-formes les plus courantes à l'heure actuelle (Windows, Mac, Linux x86, etc.) ont des octets de 8 bits.
signed char
est compris entre -128 et 127; unsigned char
est compris entre 0 et 255.
char
sera équivalent à char signé ou à char non signé, selon le compilateur, mais est un type distinct.
Si vous utilisez des chaînes de style C, utilisez simplement char
. Si vous devez utiliser des caractères pour l'arithmétique (assez rare), spécifiez explicitement signé ou non signé pour la portabilité.
Un caractère non signé est une valeur d'octet (non signé) (0 à 255). Vous pensez peut-être que "caractère" est un "caractère", mais il s’agit vraiment d’une valeur numérique. Le "caractère" normal est signé. Vous disposez donc de 128 valeurs. Ces valeurs sont mappées sur des caractères utilisant le codage ASCII. Mais dans les deux cas, ce que vous stockez en mémoire est une valeur d'octet.
En termes de valeurs directes, un caractère normal est utilisé lorsque les valeurs sont comprises entre CHAR_MIN
et CHAR_MAX
, tandis qu'un caractère non signé fournit le double de la plage de l'extrémité positive. Par exemple, si CHAR_BIT
vaut 8, la plage de char
normale est uniquement garantie de [0, 127] (car elle peut être signée ou non signée), tandis que unsigned char
sera [0. , 255] et signed char
sera [-127, 127].
En termes d’utilisation, les normes permettent aux objets de POD (plain old data) d’être convertis directement en un tableau de caractères non signés. Cela vous permet d'examiner la représentation et les modèles de bits de l'objet. La même garantie de sécurisation du type n'existe pas pour char ou char signé.
Si vous aimez utiliser différents types de longueur et de signature spécifiques, vous êtes probablement mieux avec uint8_t, int8_t, uint16_t, etc. simplement parce qu'ils font exactement ce qu'ils disent.
Un caractère non signé utilise le bit réservé au signe d'un caractère normal comme un autre nombre. Cela modifie la plage en [0 - 255] par opposition à [-128 - 127].
Généralement, les caractères non signés sont utilisés lorsque vous ne voulez pas de signe. Cela fera une différence lorsqu’il s’agira de déplacer des bits (shift étend le signe) et d’autres choses lorsqu’il s’agit d’un caractère sous forme d’octet plutôt que de l’utiliser sous forme de nombre.
un caractère non signé est le cœur de toute tromperie. Dans presque tous les compilateurs pour toutes les plateformes, un caractère non signé est simplement un BYTE. Un entier non signé de (généralement) 8 bits. qui peut être traité comme un petit entier ou un paquet de bits.
En dépendance, comme quelqu'un l'a dit, la norme ne définit pas le signe d'un caractère. vous avez donc 3 types de "char" distincts: char, char signé, char non signé.
Un certain Google a trouvé ceci , où les gens ont eu une discussion à ce sujet.
Un caractère non signé est fondamentalement un seul octet. Donc, vous utiliseriez ceci si vous avez besoin d'un octet de données (par exemple, vous pouvez l'utiliser pour définir des indicateurs à transmettre à une fonction, comme cela est souvent le cas dans l'API Windows).
unsigned char prend uniquement des valeurs positives: 0 à 255 signé car prend des valeurs positives et négatives: -128 à +127
cité dans le livre "the c programming laugage":
Le qualificatif signed
ou unsigned
peut être appliqué à char ou à tout entier. les nombres non signés sont toujours positifs ou nuls et respectent les lois de l'arithmétique modulo 2 ^ n, où n est le nombre de bits du type. Ainsi, par exemple, si les caractères sont de 8 bits, les variables non signées ont des valeurs comprises entre 0 et 255, tandis que les caractères signés ont des valeurs comprises entre -128 et 127 (dans une machine du complément à deux). Indique si les caractères simples sont signés ou non signés -dépendant, mais les caractères imprimables sont toujours positifs.