Que se passe-t-il lorsqu’un dépassement d’entier se produit dans une expression C?

J’ai le code C suivant:

uint8_t firstValue = 111; uint8_t secondValue = 145; uint16_t temp = firstValue + secondValue; if (temp > 0xFF) { return true; } return false; 

Voici l’implémentation alternative:

 uint8_t firstValue = 111; uint8_t secondValue = 145; if (firstValue + secondValue > 0xFF) { return true; } return false; 

Le premier exemple est évident, le type uint16_t est assez grand pour contenir le résultat. Lorsque j’ai essayé le deuxième exemple avec le compilateur clang sous OS / X, il a correctement renvoyé la valeur true. Que se passe-t-il là? Existe-t-il une sorte de type temporaire , plus gros, pour contenir le résultat?

    Les opérandes de + sont promus en types plus grands, nous pouvons le voir en consultant le projet de norme C99, section 6.5.6 Opérateurs additifs qui dit:

    Si les deux opérandes ont un type arithmétique, les conversions arithmétiques habituelles sont effectuées sur eux.

    et si nous passons à 6.3.1.8 Conversions arithmétiques usuelles, il est écrit:

    Sinon, les promotions sur les entiers sont effectuées sur les deux opérandes.

    et ensuite nous passons à 6.3.1.1 Booléen, caractères et nombres entiers qui dit ( emphase moi ):

    Si un int peut représenter toutes les valeurs du type d’origine, la valeur est convertie en un int; sinon, il est converti en un unsigned int. Celles-ci sont appelées promotions entières .48) Tous les autres types sont inchangés par les promotions entières.

    Ainsi, les deux opérandes de + dans ce cas seront promus au type int pour l’opération, afin qu’il n’y ait pas de dépassement de capacité.

    Remarque: Pourquoi un short doit-il être converti en int avant des opérations arithmétiques en C et C ++? explique la raison d’être des promotions.

    Le premier exemple est évident, le type uint16_t est assez grand pour contenir le résultat.

    En fait, la destination lvalue x pour l’affectation x = expr; n’a pas d’incidence sur s’il y a un débordement dans expr . Si c’est le cas, alors le résultat est ce qu’il est quelle que soit la largeur de x .

    Dans votre exemple, les “promotions entières” s’appliquent et le calcul est effectué entre les opérandes int . Cela signifie qu’il n’y a pas de débordement. Les promotions entières sont décrites dans C11 à la clause 6.3.1.1:2.

    Si vous aviez ajouté deux valeurs uint32_t , il se peut qu’il y ait eu un uint32_t (le comportement spécifié lorsqu’une opération non signée produit un résultat hors limites pour le type non signé), même si le type de la lvalue à affecter au résultat to était uint64_t .

    Oui, toute l’ arithmétique est faite dans un type qui a au moins la largeur de int . Ainsi, vos opérandes sont d’abord convertis en int , puis l’opération est effectuée. Comme dans votre premier exemple, le résultat est ensuite reconverti dans le type cible de l’affectation.

    Habituellement, ce n’est pas une bonne idée de faire du calcul avec des types étroits. Évitez que lorsque vous le pouvez, cela ne fait que compliquer les choses. Le mieux est d’éviter complètement ces types, à moins que vous n’ayez un réel problème pour stocker de grands tableaux de nombres, par exemple

    En C, les résultats intermédiaires sont au moins int , plus large si le type d’entrée est long ou un type de données plus grand.