C le comportement de dépassement d'entier lors de l'affectation à des nombres entiers de plus grande largeur
-
05-09-2019 - |
Question
Si j'exécute le code suivant dans C:
#include <stdint.h>
uint16_t a = 4000;
uint16_t b = 8000;
int32_t c = a - b;
printf("%d", c);
Il imprime correctement « -4000 » comme résultat. Cependant, je suis un peu confus: ne devrait pas y avoir un dépassement arithmétique lors de la soustraction d'un entier non signé plus de l'autre? Quelles sont les règles de coulée sont en jeu ici? Cette question semble un peu noobish, de sorte que toute référence serait grandement apprécié.
La solution
La question est en fait un peu compliqué. Opérandes d'expressions arithmétiques sont converties en utilisant des règles spécifiques que vous pouvez voir dans la section 3.2.1.5 de la standard (C89) . Dans votre cas, la réponse dépend de ce que l'uint16_t
type est. Si elle est plus petite que int
, disons short int
, puis les opérandes sont convertis en int
et vous obtenez -4000, mais sur un système 16 bits, uint16_t
pourrait être unsigned int
et la conversion à un type signé ne se produira pas automatiquement.
Autres conseils
La réponse courte est que ceux-ci sont tous promus int
au cours de la soustraction. Pour la longue réponse, regardez la section 6.3.1.1 de la C norme , où il parle de promotions entières dans les expressions arithmétiques. langue pertinente de la norme:
Si
int
peut représenter toutes les valeurs de le type d'original, la valeur est converti en unint
; sinon, il est converti en ununsigned int
. Celles-ci sont appelés les promotions entières . Tous les autres types sont inchangés par la promotions entières.
Les détails sont là aussi, mais ils obtiennent assez méchant.
Les deux opérandes sont promus à int32_t
au cours de la soustraction. Si le résultat avait été plus grande que la valeur maximale pour int32_t
vous avez vu trop-plein.
Il y a, en fait, un trop-plein, mais C ne vous dit pas.
Le débordement laisse une valeur qui se trouve être -4000 quand interprété comme un entier signé. Cela fonctionne comme prévu sur les machines de complément de 2.
Essayez d'interpréter le résultat comme non signé, et vous remarquerez que (u1-u2) évalue à un nombre apparemment sans rapport quand u1