Как проверить, не произошло ли переполнение?

Возможный дубликат:
Лучший способ обнаружение целочисленного переполнения в C / C ++

Вероятно, это вопрос новичка, но как я могу проверить, что какое-то переполнение повлияло на значение моих чисел в C. Например, при умножении целых чисел и ожидании целочисленного результата, если фактический результат был больше, чем максимальное целочисленное значение, фактический результат переделано (правда?). Итак, как я могу узнать, произошло ли что-то подобное?


person yasar    schedule 07.10.2011    source источник
comment
Предполагаемый повторяющийся вопрос касается именно значений беззнаковых, и ответы отражают это, тогда как этот вопрос является более общим и охватывает гораздо более сложный случай со знаком.   -  person caf    schedule 09.10.2011


Ответы (7)


Знаковое целочисленное переполнение похоже на деление на ноль - оно приводит к неопределенному поведению, поэтому вы должны проверить, произойдет ли это перед выполнением операции с потенциально переполнением. Как только вы переполнились, все ставки отключены - ваш код может делать все, что угодно.

Для этого пригодятся макросы *_MAX и _MIN, определенные в <limits.h>, но вы должны быть осторожны, чтобы не вызвать неопределенное поведение в самих тестах. Например, чтобы проверить, не переполнится ли a * b данный int a, b;, вы можете использовать:

if ((b > 0 && a <= INT_MAX / b && a >= INT_MIN / b) ||
    (b == 0) ||
    (b == -1 && a >= -INT_MAX) ||
    (b < -1 && a >= INT_MAX / b && a <= INT_MIN / b))
{
    result = a * b;
}
else
{
    /* calculation would overflow */
}

(Обратите внимание, что при этом избегается одна тонкая ловушка, заключающаяся в том, что вы не можете вычислить INT_MIN / -1 - такое число не гарантировано представимо и действительно вызывает фатальную ловушку на обычных платформах).

person caf    schedule 07.10.2011

В стандарте C99 есть этот раздел, объясняющий, что такое неопределенное поведение:

3.4.3
неопределенное поведение - поведение при использовании непереносимой или ошибочной программной конструкции или ошибочных данных, для которых настоящий международный стандарт не налагает требований. ПРИМЕЧАНИЕ. Возможное неопределенное поведение варьируется от полного игнорирования ситуации с непредсказуемыми результатами до поведения во время трансляции или выполнения программы задокументированным образом, характерным для среды (с выдачей диагностического сообщения или без него), до прекращения трансляции или выполнения (с выдачей диагностического сообщения).
ПРИМЕР
Примером неопределенного поведения является поведение при целочисленном переполнении.

Так что вам в значительной степени не повезло, в общем случае, постфактум, нет портативного способа обнаружения этого.
Ваш компилятор / реализация могут иметь расширения / поддержку для этого, и есть методы, чтобы избежать этого ситуаций.
См. этот вопрос для получения отличного совета: Лучший способ обнаружения целочисленное переполнение в C / C ++.

person Mat    schedule 07.10.2011

Если вы имеете в виду во время программирования, вы можете отлаживать код.

Если вы имеете в виду во время выполнения, вы можете добавить некоторые условные выражения, которые, если они превышают лимит, делают что-то.

C не знает, что делать, если расчетная доходность выходит за пределы допустимого диапазона. Вы должны избежать этого, протестировав операнды.

person M. Suleiman    schedule 07.10.2011

Проверьте это http://www.fefe.de/intof.html. Он показывает вам, как проверить, был ли фактический результат больше, чем максимальное целочисленное значение.

person Sam Casil    schedule 07.10.2011

Если полученное число меньше одного из входов.

a + b = c, если c ‹a => переполнение. изменить: чтобы быстро, это только для сложения беззнаковых целых чисел.

person Michel    schedule 07.10.2011

В общем случае невозможно узнать, произошло ли переполнение, просто глядя на результат. Однако вы можете проверить, не переполнится ли операция отдельно. Например. если вы хотите проверить, не переполняется ли a * b, где a и b - это целые числа, вам необходимо решить неравенство

a * b <= INT_MAX

То есть, если a ‹= INT_MAX / b, тогда умножение переполнится.

person janneb    schedule 07.10.2011
comment
Помните, что когда вы делите обе стороны неравенства на b, вы должны перевернуть неравенство, если b отрицательно. Также не забывайте о возможности b == 0. - person caf; 07.10.2011

Пока вы выполняете арифметические операции с целыми числами без знака или можете полагаться на специфические для реализации гарантии того, как ведет себя переполнение целых чисел со знаком, вы можете использовать различные уловки.

В случае беззнакового умножения самым простым является:

unsigned int lhs = something, rhs = something_else;
unsigned int product = lhs * rhs;

if (lhs != 0 && product/lhs != rhs) { overflow occurred }

Вряд ли будет быстро, но портативно. Проверка переполнения без знака для сложения также довольно проста - выберите один из операндов, тогда переполнение произойдет тогда и только тогда, когда сумма меньше этой.

person Steve Jessop    schedule 07.10.2011