Je suis assez confus par le code suivant:
#include #include int main(int argc, char ** argv) { uint16_t a = 413; uint16_t b = 64948; fprintf(stdout, "%u\n", (a - b)); fprintf(stdout, "%u\n", ((uint16_t) (a - b))); return 0; }
Cela retourne:
$ gcc -Wall test.c -o test $ ./test 4294902761 1001 $
Il semble que l’expression (a – b) a le type uint32_t. Je ne comprends pas pourquoi puisque les deux opérateurs sont uint16_t.
Quelqu’un peut-il m’expliquer cela?
La norme C explique cela très clairement (§6.5.6 Opérateurs additifs):
Si les deux opérandes ont un type arithmétique, les conversions arithmétiques habituelles sont effectuées sur eux.
(§6.3.1.8 Conversions arithmétiques usuelles):
… les promotions entières sont effectuées sur les deux opérandes.
(§6.3.1.1 Booléen, caractères et nombres entiers):
Si un
int
peut représenter toutes les valeurs du type d’origine, la valeur est convertie en unint
; … On les appelle les promotions entières. Tous les autres types ne sont pas modifiés par les promotions entières.
Puisque int
peut représenter toutes les valeurs de uint16_t
sur votre plate-forme, a
et b
sont convertis en int
avant l’exécution de la soustraction. Le résultat est de type int
et est transmis à printf
en tant int
. Vous avez spécifié le formateur %u
avec un argument int
; à proprement parler, cela appelle un comportement indéfini, mais sur votre plate-forme, l’argument int
est interprété comme une représentation à deux complément et imprimé.
Si vous jetez les bits d’extrémité d’un nombre (par la conversion explicite en un entier non signé de 16 bits), vous obtiendrez un résultat plus petit (compris entre 0 et 2 ^ 16-1) que avant.
C favorise les arguments en unsigned int
avant de faire la soustraction. C’est un comportement standard.
Voir, par exemple, dans une expression C où non signé signé et signé signé, quel type sera promu à quel type? pour plus de détails.