3 votes

Pourquoi le complément binaire d'une variable de 1 octet renvoie une valeur de 4 octets ?

Prenons par exemple les deux variables de 1 octet suivantes :

uint8_t x1 = 0x00;
uint8_t x2 = 0xFF;

Lors de l'impression du complément binaire, le résultat est une variable de 4 octets :

printf("%02X -> %02X; %02X -> %02X\n", x1, ~x1, x2, ~x2);
00 -> FFFFFFFF; FF -> FFFFFF00

Je sais que cela peut être "résolu" en utilisant le moulage ou le masquage :

printf("%02X -> %02X; %02X -> %02X\n", x1, (uint8_t) ~x1, x2, (uint8_t) ~x2);
00 -> FF; FF -> 00
printf("%02X -> %02X; %02X -> %02X\n", x1, ~x1&0xFF, x2, ~x2&0xFF);
00 -> FF; FF -> 00

Mais pourquoi ce comportement non intuitif en premier lieu ?

2voto

Eric Postpischil Points 36641

De nombreux processeurs informatiques ont une taille de "mot" pour la plupart de leurs opérations. Par exemple, sur une machine de 32 bits, il peut y avoir une instruction qui charge 32 bits, une instruction qui stocke 32 bits, une instruction qui ajoute un nombre de 32 bits à un autre, et ainsi de suite.

Sur ces processeurs, il peut être gênant de travailler avec d'autres tailles. Il se peut qu'il n'y ait pas d'instruction pour multiplier un nombre de 16 bits par un autre nombre de 16 bits. Le langage C a grandi sur ces machines. Il a été conçu pour que int (ou unsigned int ) était "n'importe quelle taille qui convient à la machine sur laquelle vous travaillez". char o short étaient très bien pour stocker des choses en mémoire, mais, une fois qu'ils étaient chargés de la mémoire dans les registres du processeur, le C travaillait avec eux comme s'ils étaient int .

Cela a simplifié le développement des premiers compilateurs C. Le compilateur n'avait pas besoin d'implémenter votre complément en effectuant une instruction de complément de 32 bits suivie d'une instruction ET pour supprimer les bits de poids fort indésirables. Il ne faisait qu'un simple complément de 32 bits.

Nous pourrions développer des langages différents aujourd'hui, mais le C est chargé de cet héritage.

1voto

dbush Points 8590

Lorsque vous appliquez le ~ l'opérateur à x1 y x2 les valeurs sont d'abord soumises à des promotions entières car uint8_t est plus petit qu'un int . L'opérateur est ensuite appliqué à la valeur promue.

Así que ~x1 est vraiment ~0x00000000 (c'est-à-dire 0xFFFFFFFF ) et ~x2 est vraiment ~0x000000FF (c'est-à-dire FFFFFF00 ). C'est pourquoi vous obtenez les valeurs que vous obtenez.

En outre, le %x s'attend à ce que le spécificateur de format unsigned int qu'il imprime comme tel.

Vous devez utiliser %hhx pour le spécificateur de format. Cela signifie qu'un unsigned char argument.

printf("%02hhX -> %02hhX; %02hhX -> %02hhX\n", x1, ~x1, x2, ~x2);

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X