Подтвердить что ты не робот

Как проверить переполнение со знаком в 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;

Какой из них предпочтительнее или есть лучший способ.

4b9b3361

Ответ 1

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

Ответ 2

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

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

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

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

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

Ответ 3

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