web-dev-qa-db-fra.com

Comment vérifier le débordement d'entier signé en C sans comportement indéfini?

Il y a (1):

// assume x,y are non-negative
if(x > max - y) error;

Et (2):

// assume x,y are non-negative
int sum = x + y;
if(sum < x || sum < y) error;

Lequel est préféré ou existe-t-il une meilleure façon.

26
Ganker

Le débordement d'entier est l'exemple canonique de "comportement indéfini" en C (en notant que les opérations sur des entiers non signés ne débordent jamais, elles sont définies pour boucler à la place). Cela signifie qu'une fois que vous avez exécuté x + y, s'il a débordé, vous êtes déjà arrosé. Il est trop tard pour faire une vérification - votre programme pourrait déjà avoir planté. Pensez-y comme vérifier la division par zéro - si vous attendez que la division soit exécutée pour vérifier, il est déjà trop tard.

Cela implique donc que la méthode (1) est la seule façon correcte de le faire. Pour max, vous pouvez utiliser INT_MAX de <limits.h>.

Si x et/ou y peut être négatif, alors les choses sont plus difficiles - vous devez faire le test de telle manière que le test lui-même ne puisse pas provoquer de débordement.

if ((y > 0 && x > INT_MAX - y) ||
    (y < 0 && x < INT_MIN - y))
{
    /* Oh no, overflow */
}
else
{
    sum = x + y;
}
60
caf

Vous ne pouvez vraiment vérifier le débordement qu'avec unsigned entiers et arithmatiques:

unsigned a,b,c;
a = b + c;
if (a < b) {
    /* overflow */
}

Le comportement du débordement avec des entiers signés n'est pas défini en C, mais sur la plupart des machines, vous pouvez utiliser

int a,b,c;
a = b + c;
if (c < 0 ? a > b : a < b) {
    /* overflow */
}

Cela ne fonctionnera pas sur les machines qui utilisent tout type d'arithmétique saturante

6
Chris Dodd