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

Есть (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 ответа

Целочисленное переполнение является каноническим примером "неопределенного поведения" в 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;
}

Вы можете проверить только переполнение с помощью 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 */
}

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

Вам нужно только проверить один из них. Если 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;
}
Другие вопросы по тегам