En C / C ++, à quoi unsigned char
sert un? En quoi est-ce différent d'un habitué char
?
En C / C ++, à quoi unsigned char
sert un? En quoi est-ce différent d'un habitué char
?
Réponses:
En C ++, il existe trois types de caractères distincts :
char
signed char
unsigned char
Si vous utilisez des types de caractères pour le texte , utilisez le non qualifié char
:
'a'
ou '0'
."abcde"
Il 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 à travers les inégalités - bien que si vous vous limitez à ASCII (0-127), vous êtes à peu près en sécurité.
Si vous utilisez des types de caractères sous forme de nombres , utilisez:
signed char
, ce qui vous donne au moins la gamme -127 à 127. (-128 à 127 est courant)unsigned char
, ce 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 1 (c'est-à-dire un octet), mais un octet pourrait en théorie être par exemple 32 bits. sizeof
serait toujours signaler sa taille comme1
- ce qui signifie que vous pourriez avoir sizeof (char) == sizeof (long) == 1
.
sizeof
car ce n'est pas une fonction mais un opérateur. Il est préférable de supprimer la parenthèse lors de la prise de la taille d'une variable. sizeof *p
ou sizeof (int)
. Cela indique rapidement si elle s'applique à un type ou à une variable. De même, il est également redondant de mettre des parenthèses après return
. Ce n'est pas une fonction.
char
: c'est le type de littéraux de caractères comme 'a'
ou '0'
." est vrai en C ++ mais pas en C. En C, 'a'
est un int
.
Cela dépend de l'implémentation, car la norme C ne définit PAS la signature de char
. Selon la plate-forme, char peut être signed
or unsigned
, vous devez donc demander explicitement signed char
ou unsigned char
si votre implémentation en dépend. Utilisez simplement char
si vous avez l'intention de représenter des caractères à partir de chaînes, car cela correspondra à ce que votre plate-forme met dans la chaîne.
La différence entre signed char
et unsigned char
est comme vous vous en doutez. Sur la plupart des plates-formes, signed char
sera un nombre complémentaire de deux bits de 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 char
types aient 8 bits, seulement ce sizeof(char)
retour 1
. Vous pouvez obtenir le nombre de bits dans un caractère avec CHAR_BIT
in limits.h
. Il y a peu ou pas de plateformes aujourd'hui où ce sera autre chose que 8
, cependant.
Il y a un bon résumé de ce problème ici .
Comme d'autres l'ont mentionné depuis que j'ai posté cela, il vaut mieux utiliser int8_t
et uint8_t
si vous voulez vraiment représenter de petits entiers.
CHAR_BIT
doit être d'au moins 8 bits selon la norme.
Parce que je pense 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 de unsigned char
participent à la détermination de la valeur d'un objet char non signé. Deuxièmement, unsigned char
est explicitement déclaré non signé.
Maintenant, j'ai eu une discussion avec quelqu'un sur ce qui se passe lorsque vous convertissez la valeur -1
de type int en unsigned char
. Il a refusé l'idée que le résultat unsigned char
ait tous ses bits mis à 1, car il était préoccupé par la représentation des signes. Mais il n'est pas obligé. C'est immédiatement après cette règle que 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 à plusieurs reprises une valeur de plus que la valeur maximale pouvant être représentée dans le nouveau type jusqu'à ce que la valeur soit dans la plage du nouveau type. (
6.3.1.3p2
dans un projet C99)
Voilà une description mathématique. C ++ le décrit en termes de calcul modulo, qui cède à la même règle. Quoi qu'il en soit, ce qui n'est pas garanti, c'est que tous les bits de l'entier -1
sont un avant la conversion. Alors, qu'est-ce que nous avons pour que nous puissions prétendre que le résultat unsigned char
a tous ses CHAR_BIT
bits mis à 1?
UCHAR_MAX+1
à -1
donnera une valeur dans la plage, à savoirUCHAR_MAX
Ça suffit, en fait! Donc, chaque fois que vous voulez en avoir un unsigned char
, vous le faites
unsigned char c = (unsigned char)-1;
Il s'ensuit également qu'une conversion ne consiste pas seulement à tronquer des bits d'ordre supérieur. L'événement heureux pour le complément à deux est qu'il ne s'agit que d'une troncature, mais ce n'est pas nécessairement le cas pour les autres représentations de signes.
UCHAR_MAX
?
(unsigned type)-1
c'est une sorte d'idiome. ~0
n'est pas.
int x = 1234
et char *y = &x
. Représentation binaire de 1234
is 00000000 00000000 00000100 11010010
. Ma machine est peu endienne donc elle l'inverse et stocker en mémoire 11010010 00000100 00000000 00000000
LSB vient en premier. Maintenant partie principale. si j'utilise printf("%d" , *p)
. printf
lira premier octet 11010010
que la sortie est , -46
mais 11010010
est 210
alors pourquoi faut - il imprimer -46
. Je suis vraiment confus, je suppose que certains chars en promotion entière font quelque chose mais je ne sais pas.
Comme par exemple les utilisations du caractère non signé :
unsigned char
est souvent utilisé en infographie, qui attribue très souvent (mais pas toujours) un seul octet à chaque composant de couleur. Il est courant de voir une couleur RGB (ou RGBA) représentée par 24 (ou 32) bits, chacun un unsigned char
. Étant donné que les unsigned char
valeurs se situent dans la plage [0,255], les valeurs sont généralement interprétées comme:
Vous vous retrouveriez donc avec du rouge RVB comme (255,0,0) -> (100% rouge, 0% vert, 0% bleu).
Pourquoi ne pas utiliser un signed char
? Le décalage arithmétique et binaire devient problématique. Comme expliqué précédemment, signed char
la plage de a est essentiellement décalée de -128. Une méthode très simple et naïve (pour la plupart inutilisée) pour convertir le RVB en niveaux de gris consiste à faire la moyenne des trois composantes de couleur, mais cela pose des problèmes lorsque les valeurs des composantes de couleur sont négatives. Le rouge (255, 0, 0) fait la moyenne de (85, 85, 85) lors de l'utilisation de l' unsigned char
arithmétique. Cependant, si les valeurs étaient signed char
s (127, -128, -128), nous nous retrouverions avec (-99, -99, -99), ce qui serait (29, 29, 29) dans notre unsigned char
espace, ce qui est incorrect .
Si vous souhaitez utiliser un caractère comme un petit entier, la façon la plus sûre de le faire est d'utiliser les types int8_t
et uint8_t
.
int8_t
et uint8_t
sont facultatives et ne sont pas définis sur des architectures où la taille des octets ne sont pas exactement 8 bits. Inversement, signed char
et unsigned char
sont toujours disponibles et garantis pour contenir au moins 8 bits. C'est peut-être un moyen courant mais pas le plus sûr .
signed char
et unsigned char
? Ou recommanderiez-vous une meilleure alternative "plus sûre" dans ce cas particulier? Par exemple, pour s'en tenir aux types entiers "réels" signed int
et à la unsigned int
place pour une raison quelconque?
signed char
et unsigned char
est portable pour toutes les implémentations conformes et économisera de l'espace de stockage mais peut entraîner une augmentation de la taille du code. Dans certains cas, on économiserait plus d'espace de stockage en stockant de petites valeurs dans des champs binaires ou des bits simples de types entiers réguliers. Il n'y a pas de réponse absolue à cette question, la pertinence de cette approche dépend du cas d'espèce. Et cette réponse ne répond pas de toute façon à la question.
char
et unsigned char
ne sont pas garantis comme étant de type 8 bits sur toutes les plates-formes - ils sont garantis comme étant de 8 bits ou plus. Certaines plates-formes ont des octets 9 bits, 32 bits ou 64 bits . Cependant, les plates-formes les plus courantes aujourd'hui (Windows, Mac, Linux x86, etc.) ont des octets 8 bits.
signed char
a une plage de -128 à 127; unsigned char
a une plage de 0 à 255.
char
sera équivalent à char signé ou 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 pour la portabilité.
An unsigned char
est une valeur d'octet non signée (0 à 255). Vous pensez peut-être char
en termes d'être un "personnage" mais c'est vraiment une valeur numérique. Le régulier char
est signé, vous avez donc 128 valeurs, et ces valeurs sont mappées à des caractères à l'aide du 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 à l'extrémité positive. Par exemple, si la valeur CHAR_BIT
est 8, la plage de valeurs régulières char
est uniquement garantie d'être [0, 127] (car elle peut être signée ou non) tandis que unsigned char
sera [0, 255] et signed char
sera [-127, 127].
En termes d'utilisation, les normes permettent aux objets de POD (données anciennes simples) d'être directement convertis en un tableau de caractères non signés. Cela vous permet d'examiner la représentation et les motifs binaires de l'objet. La même garantie de punition de type sûre n'existe pas pour le caractère ou le caractère signé.
unsigned char
, pas un tableau en particulier, et toute "conversion" n'est définie formellement qu'en copiant de l'objet vers un véritable tableau déclaré de unsigned char
& inspectant ensuite ce dernier. Il n'est pas clair si le OU peut être directement réinterprété comme un tel tableau, avec les tolérances pour l'arithmétique du pointeur qu'il impliquerait, c'est-à-dire si "séquence" ==
"tableau" dans cette utilisation. Il y a un problème principal n ° 1701 dans l'espoir de clarifier cela. Heureusement, car cette ambiguïté me dérange vraiment récemment.
unsigned char
du bloc ++ptr
opératoire, puis continuer à utiliser à partir de là pour en lire chaque octet ... mais AFAICT, ce n'est pas spécifiquement défini comme étant autorisé, donc nous sommes laissé à déduire que c'est «probablement OK» de nombreux autres passages (et à bien des égards, la simple existence de memcpy
) dans la norme, semblable à un puzzle. Ce qui n'est pas idéal. Eh bien, peut-être que le libellé s'améliorera éventuellement. Voici le problème CWG que j'ai mentionné mais qui manquait d'espace pour créer un
unsigned char
est le cœur de la supercherie. Dans presque TOUS les compilateurs pour TOUTES les plateformes, un unsigned char
est simplement un octet et 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 char. de sorte que vous avez 3 différents char
types: char
, signed char
, unsigned char
.
Si vous aimez en utilisant différents types de longueur spécifique et signedness, vous êtes probablement mieux avec uint8_t
, int8_t
, uint16_t
, etc simplement parce qu'ils font exactement ce qu'ils disent.
Certains googleurs ont trouvé cela , où les gens ont eu une discussion à ce sujet.
Un caractère non signé est essentiellement un octet unique. Donc, vous l'utiliseriez si vous avez besoin d'un octet de données (par exemple, vous souhaitez peut-être l'utiliser pour activer et désactiver les indicateurs à transmettre à une fonction, comme cela se fait souvent dans l'API Windows).
Un caractère non signé utilise le bit réservé au signe d'un caractère normal comme un autre nombre. Cela change 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 lorsque vous faites des choses comme le décalage des bits (décalage étend le signe) et d'autres choses lorsque vous traitez un caractère comme un octet plutôt que de l'utiliser comme un nombre.
cité à partir du livre "le c programmation laugage":
Le qualificatif signed
ou unsigned
peut être appliqué à char ou à n'importe quel entier. les nombres non signés sont toujours positifs ou nuls et obéissent aux lois du module arithmétique 2 ^ n, où n est le nombre de bits du type. Ainsi, par exemple, si les caractères sont de 8 bits, les variables de caractères non signés 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 complémentaire à deux). -dépendant, mais les caractères imprimables sont toujours positifs.
signed char
et les unsigned char
deux représentent 1 octet, mais ils ont des plages différentes.
Type | range
-------------------------------
signed char | -128 to +127
unsigned char | 0 to 255
Dans signed char
si nous considérons char letter = 'A'
, 'A' est un binaire de 65 pouces ASCII/Unicode
, si 65 peut être stocké, -65 peut également être stocké. Il n'y a pas de valeurs binaires négatives ASCII/Unicode
là-dedans sans avoir à se soucier des valeurs négatives.
Exemple
#include <stdio.h>
int main()
{
signed char char1 = 255;
signed char char2 = -128;
unsigned char char3 = 255;
unsigned char char4 = -128;
printf("Signed char(255) : %d\n",char1);
printf("Unsigned char(255) : %d\n",char3);
printf("\nSigned char(-128) : %d\n",char2);
printf("Unsigned char(-128) : %d\n",char4);
return 0;
}
Production -:
Signed char(255) : -1
Unsigned char(255) : 255
Signed char(-128) : -128
Unsigned char(-128) : 128