Pourquoi printf ajoute-t-il un caractère de 8 bits à 32 bits?

char byte = 0xff; printf("%lu\n", sizeof(byte)) // Output is '1' printf("%x\n", byte); // Output is 'ffffffff' 

Si la taille d’un byte n’est qu’un octet, pourquoi alors printf() se comporte-t-il comme s’il s’agissait de quatre octets?

Formellement, votre programme présente un comportement non défini: La spécification de format %x attend un argument de type unsigned int , mais vous transmettez un int , comme expliqué ci-dessous (hat tip @R). Ceci est inoffensif dans la pratique sur les machines modernes à complément à deux, puisque int et unsigned ont des dispositions de bits compatibles. Mais là encore, techniquement, il s’agit d’un comportement indéfini et il serait judicieux de le corriger, comme dans printf("%x\n", (unsigned)byte); .

Les règles de passage de parameters à des fonctions variadiques stipulent que tous les types intégraux plus petits que int sont promus en int. Sinon, comment printf verrait-il, en voyant %x , s’il faut extraire un octet ou quatre octets de la stack? De la norme:

5.2.2p7:
Lorsqu’il n’y a pas de paramètre pour un argument donné, l’argument est passé de manière à ce que la fonction récepsortingce puisse obtenir la valeur de l’argument en appelant va_arg (18.10)... Si l’argument a un type intégral ou une énumération soumis à lors des promotions intégrales (4.5), ou d’un type à virgule flottante soumis à la promotion à virgule flottante (4.6), la valeur de l’argument est convertie en type promu avant l’appel.

Voici comment votre personnage se transforme en int . Il n’est pas spécifié si char est signé ou non, mais apparemment, sur la plate-forme utilisée, vous utilisez un type signé. Donc, il est étendu aux signes lorsqu’il est promu à int . 0xff est (char)-1 et 0xffffffff est (int)-1 .

Je pense que c’est dû à la integer promotion

Un bon article de blog sur ce concept: http://www.idryman.org/blog/2012/11/21/integer-promotion/

Vous avez appelé comportement indéfini en transmettant le type d’argument incorrect à printf . Le spécificateur %x nécessite un argument de type unsigned int , mais vous avez passé (en raison des promotions par défaut) un unsigned int signé. Ceci est sans doute valable si la valeur de l’argument signé signé n’est pas négative, mais sur votre système, un caractère simple se trouve être un type signé, donc byte contient le résultat de l’application d’une conversion définie par l’ 0xff à 0xff ; le résultat habituel de cette conversion est -1.

Un caractère est signé 8 bits. Le format "%x\n" dit d’imprimer un entier. Donc, la valeur d’ byte est le signe étendu à un entier. Etant donné qu’un caractère de 0xff est, dans ce contexte, une valeur à 8 bits de -1 , printf imprime simplement la valeur entière hexadécimale d’un -1 , qui est ffffffff .