tapez promotion en C

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 un int ; … 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.