Affecter des nombres négatifs à un int non signé?

Dans le langage de programmation C, unsigned int est utilisé pour stocker uniquement les valeurs positives. Cependant, lorsque j’exécute le code suivant:

 unsigned int x = -12; printf("%d", x); 

La sortie est toujours -12. Je pensais que cela aurait dû être imprimé: 12, ou est-ce que je comprends mal quelque chose?

Le -12 à droite de votre signe égal est défini comme un entier signé (probablement 32 bits) et aura la valeur hexadécimale 0xFFFFFFF4 . Le compilateur génère du code pour déplacer cet entier signé dans votre entier non signé x qui est également une entité 32 bits. Le compilateur suppose que vous avez seulement une valeur positive à droite du signe égal, donc il déplace simplement tous les 32 bits dans x . x maintenant la valeur 0xFFFFFFF4 qui est 4294967284 si elle est interprétée comme un nombre positif. Mais le format printf de %d indique que les 32 bits doivent être interprétés comme un entier signé, vous obtenez donc -12 . Si vous aviez utilisé %u cela aurait imprimé 4294967284 .

Dans les deux cas, vous n’obtenez pas ce que vous attendez, car le langage C “fait confiance” au rédacteur de code pour demander uniquement des choses “sensibles”. Ceci est courant en C. Si vous vouliez assigner une valeur à x et que vous ne saviez pas si la valeur du côté droit des équations était positive, vous pourriez avoir écrit unsigned int x = abs(-12); et forcé le compilateur à générer du code pour prendre la valeur absolue d’un entier signé avant de le déplacer vers l’entier non signé.

Le int est déconnecté, mais vous avez dit à printf de le regarder comme un int signé.

Essayer

 unsigned int x = -12; printf("%u", x); 

Il n’imprimera pas “12”, mais imprimera la valeur maximale d’un int non signé moins 11.

L’exercice au lecteur est de savoir pourquoi 🙂

Passer% d à printf indique à printf de traiter l’argument comme un entier signé, indépendamment de ce que vous avez réellement passé. Utilisez% u pour imprimer comme non signé.

Tout est lié à l’interprétation de la valeur.

Si vous supposez des entiers signés et non signés à 16 bits, voici quelques exemples qui ne sont pas tout à fait corrects, mais illustrent le concept.

0000 0000 0000 1100 unsigned int, et signé int value 12

1000 0000 0000 1100 signée int -12 et un grand entier non signé.

Pour les entiers signés, le bit à gauche est le bit de signe. 0 = positif 1 = négatif

Pour les entiers non signés, il n’y a pas de bit de signe. le bit de gauche vous permet de stocker un nombre plus important à la place.

Donc, la raison pour laquelle vous ne voyez pas ce à quoi vous vous attendez est la suivante.

unsigned int x = -12, prend -12 comme un entier et le stocke dans x. x est non signé, alors ce qui était un bit de signe, est maintenant un morceau de la valeur.

printf vous permet de dire au compilateur comment vous voulez afficher une valeur.

% d signifie l’afficher comme s’il s’agissait d’un int signé. % u signifie l’afficher comme s’il s’agissait d’un entier non signé.

c vous permet de faire ce genre de choses. Vous le programmeur êtes en contrôle.

Un peu comme une arme à feu. C’est un outil. Vous pouvez l’utiliser correctement pour faire face à certaines situations ou pour supprimer l’un de vos orteils.

un cas éventuellement utile est le suivant

unsigned int allBitsOn = -1;

Cette valeur particulière définit tous les bits à 1

1111 1111 1111 1111

cela peut être utile parfois.

 printf('%d', x); 

Signifie imprimer un entier signé. Vous devrez écrire ceci à la place:

 printf('%u', x); 

En outre, il ne sera toujours pas imprimé “12”, il va être “4294967284”.

Ils stockent des valeurs positives. Mais vous produisez la valeur positive (très élevée) sous la forme d’un entier signé, de sorte qu’elle soit réinterprétée (d’une manière définie par l’implémentation, j’appendai).

Utilisez le drapeau de format "%u au lieu de cela.

Votre programme a un comportement indéfini car vous avez transmis le mauvais type à printf (vous lui avez dit que vous alliez passer un int mais vous avez passé un unsigned int ). Considérez-vous chanceux que la chose la plus “facile” pour l’implémentation à faire était simplement d’imprimer en silence la mauvaise valeur et de ne pas sauter à un code qui fait quelque chose de dangereux …

Ce qui vous manque, c’est que printf (“% d”, x) s’attend à ce que x soit signé, donc bien que vous affectiez -12 à x, il est interprété comme un complément à 2, ce qui serait un très grand nombre. Cependant, lorsque vous transmettez ce très grand nombre à printf, il l’interprète comme signé, le traduisant ainsi correctement vers -12.

La syntaxe correcte pour imprimer un non signé dans l’impression f est “% u” – essayez ceci et voyez ce qu’il fait!

L’affectation d’une valeur négative à un entier non signé ne calcule pas la valeur absolue du négatif: elle interprète comme non signé int la représentation binary de la valeur négative, à savoir 4294967284 (2 ^ 32 – 12).

printf (“% d”) effectue l’interprétation inverse. C’est pourquoi votre programme affiche -12.

Lorsque vous essayez d’afficher la valeur int, vous la transmettez à un argument (int) et non à un argument (unsigned int), ce qui provoque l’impression de -12 et non pas 4294967284. Les entiers sont stockés au format hexadécimal et -12 pour int est le même que 4294967284 pour unsigned int au format hexadécimal .. C’est pourquoi “% u” imprime la bonne valeur que vous voulez et pas “% d” .. Cela dépend de votre type d’argument..GOOD LUCK!

Lorsque le compilateur convertit implicitement -12 en un entier non signé, la représentation binary sous-jacente rest inchangée. Cette conversion est purement sémantique. Le bit de signe de l’entier de complément à deux devient le bit le plus significatif de l’entier non signé. Ainsi, lorsque printf traite l’entier non signé comme un entier signé avec% d, il verra -12.

Dans un contexte général, lorsque seuls des nombres positifs peuvent être stockés, les nombres négatifs ne sont pas stockés explicitement mais leur complément à 2 est stocké. De la même manière, le complément à 2 de -12 sera stocké dans ‘x’ et vous utiliserez %u pour l’obtenir.

int et unsigned int sont utilisés pour allouer un nombre d’octets pour stocker une valeur rien de plus.

Le compilateur doit donner des avertissements sur la non-correspondance signée, mais cela n’affecte pas les bits de la mémoire représentant la valeur -12.

% x,% d,% u etc. indique au compilateur comment interrompre un certain nombre de bits lorsque vous les imprimez.