как правильно отлавливать переполнения численных типов?

sergey_m

Вот эта программа ничего не пишет, как и следовало ожидать.

#include <limits.h>

int main
{
unsigned int i = UINT_MAX - 5;

if (i + 10 > UINT_MAX)
echo("Overflow detected\n");
}

Вопрос: а как же правильно сделать эту проверку?

Julie16

i > UINT_MAX - 10?

sergey_m

Иопт. Всё гениальное просто.

Marinavo_0507

Может так?

i1 = i + 10;
if (i1 < i) { /* overflow */ }
i=i1;

Ivan8209

В сях --- никак.
Только писать с учётом возможности переполнения.
(На самом деле --- задрало. Лисп --- рулит.)
---
...Я работаю антинаучным аферистом...

Ivan8209

Можно ещё расшириться до long int-а.
---
...Я работаю антинаучным аферистом...

sergey_m

> Можно ещё расшириться до long int-а.
Ну это означает уклониться от проблемы, а не решить её. Кроме того, в ряде случаев такое решение неприемлемо.

Julie16

Это неправильный подход. Насколько я помню, стандартом не описывается как происходит overflow. Поэтому проверка i1 < i - это архитектурозависимо.

Marinavo_0507

В жопу такой стандарт, на нём тогда точно ничего не написать по-нормальному.

Julie16

Другое дело что я не знаю ни одной архитектуры где overflow происходит не таким образом... Но это еще ни о чем не говорит.

Ivan8209

А что ты хотел?
А другого стандарта, судя по всему, нет.
---
...Я работаю антинаучным аферистом...

Marinavo_0507

Можно писать на одном из языков, где встроенная арифметика - длинная.
Медленно, конечно.

Ivan8209

А компилятор предоставляет хоть какой-то доступ к состоянию процессора?
Вообще, эта задача очень машинозависима.
Либо ты извращаешься и пишешь так, чтобы никогда не доползать до пределов.
---
...Я работаю антинаучным аферистом...

Ivan8209

Писать --- можно быстро.
Оптимизировать должен оптимизатор.
Можно отыскать процессор, где отлавливать переполнение
невозможно вообще.
---
...Я работаю антинаучным аферистом...

Marinavo_0507

> Оптимизировать должен оптимизатор.
Кому должен?
> Можно отыскать процессор, где отлавливать переполнение
> невозможно вообще.
Искать, чтоб выкинуть обратно в помойку? А зачем?

Julie16

И как же ты предлагаешь соптимизировать операцию сравнения + возможный прыжок после каждой арифметической операции? Ню-ню.

Marinavo_0507

Пример.
В ядре Linux на 32-битных архитектурах счётчик принятых и полученных байт 32-битный.
Очень неудобно, часто переполняется (примерно 30 секунд при скорости 1Гбит/с).
Если хочешь ну хотя бы график загрузки нарисовать, то нужно
1) часто опрашивать счётчик
2) делать таки сабж
Почему не введут хотя бы 64-битный счётчик?
Правильный ответ - после получения ваших вариантов.

Julie16

Может оно нах никому не надо?
PS: я в этом не копенгаген, прошу ногами не пинать

Marinavo_0507

Очень даже надо.
При скорости 10Гбит/c - уже через 3 секунды переполнение будет

Julie16

> And last, to try to help you understand, one of the reasons
> that it hasn't already been done is that 64-bit
> arithmetic on a 32-bit processor requires using a lock
> to make it atomic, and that's expensive.

Marinavo_0507

Ну да, это основная причина.

sergey_m

Ответ правильный.

Ivan8209

Ну так, тогда вставляй соответствующие J(N)O, B(N)O(V)
или как оно там ещё может называться вручную.
Си --- это тебе не PL.
---
...Я работаю антинаучным аферистом...

bleyman

i1 = i + 10;
if (i1 < i) { /* overflow */ }
i=i1;
Вообще да. Имхо это на любой архитектуре сработает корректно. Ну то есть overflow == переход за максимально допустимое значение, если инты образуют простое кольцо (не в математическом смысле, наверное) по операции ++, то такой проверки достаточно. Всегда достаточно, замечу, нету такого положительного числа, чтобы overflow произошёл два раза. Наверное если подумать, то можно написать проверку на оба переполнения (и вверх и вниз) для a + b и произвольных а, b.
По поводу железной проверки - вы чо, ваще? В х86 есть два прекрасных флага - OV и CF, которые прекрасно описывают все переходы через разные важные границы как для signed, так и unsigned сложения/вычитания.

Marinavo_0507

> В х86 есть два прекрасных флага - OV и CF, которые прекрасно описывают все переходы через разные важные границы как для signed,
> так и unsigned сложения/вычитания.
Какой компилятор C умеет их использовать для проверки переполнения?

bleyman

Ну вообще, насколько я помню, их можно откуда то узнать и использовать самостоятельно.

Marinavo_0507

самостоятельно?
ассемблерной вставкой типа?
говнопредложение

bleyman

Ну вообще да, конечно. Тем не менее если скорость не так важна, пиши проверку if ( a + increment < a которая сработает корректно на любой архитектуре вообще.

evgen5555

ассемблерной вставкой типа?
говнопредложение
А чем тебя смущают ассемблерные вставки, тем более в таком говнослучае?

Ivan8209

А если там сложение с насыщением?
---
...Я работаю антинаучным аферистом...

gopnik1994

потому что платформозависимо
а Си должен рулить - ему по статусу положено.

Ivan8209

Вот как раз Си ничего не должен:
в K[A-D]11 арифметика была дополнительная до двух.
---
...Я работаю антинаучным аферистом...

xronik111

Пробегало недавно в gcc-help: Inline assembly for detecting int32 overflow on IA32 and AMD64

Ivan8209

Это не только использует ассемблерные вставки,
но ещё и нестандартные особенности гнутого диалекта.
---
...Я работаю антинаучным аферистом...

bleyman

Оммм. А если со встроенным range-checking и кидает какой-нить ран-еррор при переполнении (как в паскале)?

Ivan8209

То есть, опять приходим к зависимости от особенностей среды
исполнения не предусмотренных языком.
---
...Я работаю антинаучным аферистом...

bleyman

Да, я всегда говорил что без виртуальной машины, описывающей базовые действия над базовыми типами, кроссплатформенности очень тяжело достичь.
Хотя я стандарт С не читал, и не могу с уверенностью сказать, что там не заявляено в явном виде, что сложение - оно без насыщения.
Оставить комментарий
Имя или ник:
Комментарий: