Débordement d’entier C

Je travaillais avec des nombres entiers en C, essayant d’explorer plus en détail quand et comment un débordement se produit.

J’ai remarqué que lorsque j’ai ajouté deux nombres positifs, dont la sum déborde, j’ai toujours un nombre négatif.

Par contre, si j’ajoutais deux nombres négatifs, dont la sum débordait, j’obtenais toujours un nombre positif (y compris 0).

J’ai fait peu d’expériences, mais j’aimerais savoir si cela est vrai dans tous les cas.

Les débordements d’entiers sont un comportement non défini en C.

C dit une expression impliquant des dépassements d’ entiers entiers, si son résultat après les conversions arithmétiques habituelles est d’un type signé et ne peut pas être représenté dans le type du résultat. Les expressions d’assignation et de transtypage constituent une exception car elles sont régies par les conversions d’entiers.

Les expressions de type non signé ne peuvent pas déborder, elles encapsulent, par exemple, 0U - 1 est UINT_MAX .

Exemples:

 INT_MAX + 1 // integer overflow UINT_MAX + 1 // no overflow, the resulting type is unsigned (unsigned char) INT_MAX // no overflow, integer conversion occurs 

Ne laissez jamais une expression entière se chevaucher. Les compilateurs modernes (comme gcc ) tirent parti des débordements d’entiers en tant que comportement indéfini pour effectuer divers types d’optimisations.

Par exemple:

 a - 10 < 20 

quand a est de type int après promotion, l'expression est réduite dans gcc (lorsque l'optimisation est activée) à:

 a < 30 

Il tire parti du comportement indéfini de l'expression lorsque a est compris dans la plage INT_MIN + 10 - 1 à INT_MIN .

Cette optimisation ne peut pas être effectuée lorsque a est unsigned int car si a vaut 0 , alors a - 10 doit être évalué comme étant UINT_MAX - 9 (pas de comportement indéfini). L’optimisation de a - 10 < 20 à a < 30 conduirait alors à un résultat différent de celui requirejs lorsque a vaut de 0 à 9 .

Le débordement d’entiers signés est un comportement non défini en C, il n’y a donc aucune garantie.

Cela dit, un comportement classique, ou modulo arithmétique 2 N , où N est le nombre de bits du type, est un comportement courant. Pour ce comportement, en effet si une sum déborde, le résultat a le signe opposé des opérandes.

Formellement, le comportement de l’arithmétique signée en cas de dépassement de capacité n’est pas défini. tout peut arriver et c’est «correct». Cela contraste avec l’arithmétique non signée, où le dépassement de capacité est complètement défini.

Dans la pratique, de nombreux compilateurs plus anciens utilisaient une arithmétique signée qui débordait comme vous le décrivez. Cependant, GCC moderne apporte des modifications à son fonctionnement et vous seriez très mal avisé de vous fier à ce comportement. Cela peut changer à tout moment lorsque quelque chose dans l’environnement où votre code est compilé change – le compilateur, la plate-forme, …