Как проверить на целочисленное переполнение со знаком в C без неопределенного поведения? - PullRequest
26 голосов
/ 14 апреля 2010

Есть (1):

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

А (2):

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

Что предпочтительнее или есть лучший способ.

Ответы [ 3 ]

60 голосов
/ 14 апреля 2010

Целочисленное переполнение является каноническим примером «неопределенного поведения» в C (отмечая, что операции над целыми числами без знака никогда не переполняются, они вместо этого определены для переноса). Это означает, что после того, как вы выполнили x + y, если оно переполнилось, вы уже в рукаве. Слишком поздно делать какие-либо проверки - ваша программа могла уже потерпеть крах. Думайте об этом, как о проверке деления на ноль - если вы ждете, пока разделение будет выполнено, проверить, уже слишком поздно.

Таким образом, это означает, что метод (1) является единственным правильным способом сделать это. Для max вы можете использовать INT_MAX из <limits.h>.

Если x и / или y могут быть отрицательными, то все сложнее - вам нужно выполнить тест таким образом, чтобы сам тест не мог вызвать переполнение.

if ((y > 0 && x > INT_MAX - y) ||
    (y < 0 && x < INT_MIN - y))
{
    /* Oh no, overflow */
}
else
{
    sum = x + y;
}
7 голосов
/ 14 апреля 2010

Вы можете проверить только переполнение с помощью unsigned целых и арифметических чисел:

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

Поведение переполнения целыми числами со знаком не определено в C, но на большинстве машин вы можете использовать

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

Это не будет работать на машинах, которые используют любые насыщающие арифметики

0 голосов
/ 14 апреля 2010

Вам нужно только проверить один из них. Если x + y переполнится, оно будет меньше, чем x и y. Следовательно:

int sum = x + y;
if (sum < x) error;

должно быть достаточно.

На следующем сайте есть много вещей о целочисленном переполнении:

http://www.fefe.de/intof.html

Если вы хотите обработать отрицательные числа, его можно расширить:

int sum = x + y;
if (y >= 0) {
   if (sum < x) error;
} else {
   if (sum > x) error;
}
...