LINUX.ORG.RU

А тут все вкурсе что бывает при переполении int?

 ,


4

4

Задача. Монотонно растущий счетчик времени который в какой то момент может переполнится.
Код делает типовые операции

uint16_t startTime = millis();
...
uint16_t stopTime = millis();
uint16_t runSpeed = stopTime - startTime;

Вопрос что будет если startTime будет равно 65535 а stopTime будет равно 1?
Какой будет runSpeed?
Код теста
//# ./a 1 - 65535
#include <stdio.h>
#include <stdint.h>

int main(int argc, char * argv[]) {
  uint16_t a = atoi(argv[1]);
  uint16_t b = atoi(argv[3]);
  
  printf("%d", (uint16_t)(a - b));
  
  return 0;
}

Итого все хорошо 1 - 65535 будет равно 2 как и предполагалось. Спасибо бинарной логике процессора. И никаких лишних проверок сравнений лепить не надо.

★★★★

Что это такое? Нужно писать так, чтобы работало везде. Под мобильные GPU (крайне массовая и современная платформа) это даже не скомпилировать, переделывай.

anonymous
()

А тут все вкурсе

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

LamerOk ★★★★★
()

Ответ на вопрос в заголовке - неопределенное поведение. Переполнение знакового целого - UB. Переполнение беззнакового - просто работа в кольце вычетов по модулю 2^n.

roof ★★
()

А тут все вкурсе что бывает при переполении int?

uint16_t

Еще один не отличает signed и unsigned.

Итого все хорошо

А теперь представь, что будет, если между снятием показаний счётчик успеет переполниться дважды.

Deleted
()
Последнее исправление: Deleted (всего исправлений: 1)

В заголовке знаковый, в коде беззнаковый, первое, емнип, ub, второе нет. Уж определитесь где мухи а где котлеты

anonymous
()

Хочешь узнать,что будет? Почитай историю падения ракеты Ариан-5.

le_legioner ★★
()
Последнее исправление: le_legioner (всего исправлений: 1)

что бывает при переполении int?

приходит Царь?

mos ★★☆☆☆
()

Переполнение int - харам. Никогда, ни при каких обстоятельствах, не допускай его

Manhunt ★★★★★
()

Не знаю про int, но при переполнении (недополнении?) unsigned short, случается ядерный Ганди.

Deleted
()

ub

Ага, а потом опять что-то будет в духе:

Диагностика V1026 создана по мотивам дискуссии на форуме linux.org.ru. Программист жаловался на глюк в компиляторе GCC 8, но, как затем выяснилось, виной всему является некорректный код, приводящий к неопределённому поведению. Давайте рассмотрим этот случай.

Весь текст: https://habr.com/ru/company/pvs-studio/blog/426905/

anonymous
()

А тут все вкурсе что бывает при переполении int?

я думал об этом еще рассказывают на уроках информатики в школе...

anonymous2 ★★★★★
()
Ответ на: комментарий от Deleted

Обычно такой код пишут, когда уверены, что дважды переполнится он не успеет. Риалтайм же, всё предсказуемо.

KivApple ★★★★★
()
Ответ на: комментарий от anonymous

В заголовке знаковый, в коде беззнаковый, первое, емнип, ub, второе нет. Уж определитесь где мухи а где котлеты

Там UB, при условии, что на его платформе sizeof(int) > sizeof(uint16_t) (что вообще должно быть). Это потому, что ТС не знает, что при выполнение арифметических операций:

6.3.1.1/2 If an int can represent all values of the original type, the value is converted to an int; otherwise, it is converted to an unsigned int.

И поэтому не понимает, что для компилятора код

uint16_t runSpeed = stopTime - startTime;

выглядит так:

uint16_t runSpeed = (uint16_t)(((int)stopTime) - ((int)startTime));
Deleted
()
Последнее исправление: Deleted (всего исправлений: 1)

что бывает при переполении int?

Зависит от языка и кода.

Например, во Free Pascal'е по дефолту отключена проверка переполнения.

program intoverflowtest;
uses sysutils;
var
        a: Integer;
        b: Int64;
begin
        a := MaxInt;
        b := $7fffffffffffffff;
        inc(a);
        inc(b);
        writeln(a);
        writeln(b);
end.
$ ./intoverflowtest
-32768
-9223372036854775808
Но её можно включить строчкой
{$OVERFLOWCHECKS ON}
$ ./intoverflowtest
An unhandled exception occurred at $00000000004010E5:
EIntOverflow: Arithmetic overflow
  $00000000004010E5

Кстати, приведённый пример в Turbo Pascal'е не сработал бы.

Overflow checking behaviour is not the same as in Turbo Pascal since all arithmetic operations are done via 32-bit or 64-bit values. Furthermore, the Inc() and Dec standard system procedures are checked for overflow in Free Pascal, while in Turbo Pascal they are not.

saahriktu ★★★★★
()

Кстати, а как к переменной нормально добавить проверку переполнения?

Deleted
()
Ответ на: комментарий от Deleted

Кстати, а как к переменной нормально добавить проверку переполнения?

Нормально - никак.

Сконвертировать в больший размер, вычислить там и проверить, вписывается ли в границы исходного типа.

Или хаки типа:


unsigned a = ...;
unsigned b = ...;
unsigned c;

if (UINT_MAX - b < a)
{
    обработка переполнения
}
else
{
    c = a + b;
}

Deleted
()
Ответ на: комментарий от Deleted

Ну так нормально - никак.

Ну вот. Лет через 30 комитет родит какой-нибудь C49, в котором наконец-то вспомнят, что у компьютеров переполнение целого не магия, а штатная операция, требующая штатной обработки. Спасибо Ричи со товарищи.

Но лучше так чем вот как выше.

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

Deleted
()
Ответ на: комментарий от Deleted

У меня кстати где-то лежит заготовка для мини-библиотеки, реализующей unsigned int with NaN. Чтобы можно было вычислить длинное выражение, а в конце просто проверить на value != UINT_NAN. Но это сокращает диапазон допустимых значений целого на единицу, т.к. UINT_MAX == UINT_NAN.

Deleted
()
Последнее исправление: Deleted (всего исправлений: 1)
Ответ на: комментарий от Deleted

Уж точно не переносимость из одного облака в другое в виде файла.

То самое: переносимость между разными реализациями компиляторов.

grem ★★★★★
()

счетчик перейдет в состояние квантовой суперпозиции

Minona ★★☆
()
Ответ на: комментарий от Deleted

Там UB, при условии, что на его платформе sizeof(int) > sizeof(uint16_t)

Чому?

anonymous
()

будет равно 2 как и предполагалось

Да, только непонятно сколько кругов по 2^16 намотано, чтобы получилось это 2.

no-such-file ★★★★★
()
Ответ на: комментарий от anonymous

Тут еще верно заметили что во избежание багов лучше писать не

  uint16_t endTime = millis() + timeout; while(foo && millis() < endTime) {
    bar
  }

а
  uint16_t startTime = millis(); while(foo && millis() - startTime < timeout) {
    bar
  }

тк первый вариант в случае переполнения даст 65530 < 150 например и цыкл никогда не запустится

bga_ ★★★★
() автор топика
Ответ на: комментарий от anonymous

Нужно писать так, чтобы работало везде.

Кто тебе такую глупость сказал?

Dudraug ★★★★★
()
Ответ на: комментарий от Manhunt

Переполнение int - харам. Никогда, ни при каких обстоятельствах, не допускай его

Вот с этим соглашусь.

Dudraug ★★★★★
()

А что тебе не нравится? Все вполне логично. У меня на STM32 счетчик миллисекунд так и работает: подумаешь, переполнится — станет единицей, все равно все мат. операции по вычислению разницы времени будут правильными.

anonymous
()
Ответ на: комментарий от Deleted

А где тут UB? Разница int со значениями от 0 до 65535 никак не даст переполнения. Преобразование в uint16_t тоже определено.

i-rinat ★★★★★
()
Ответ на: комментарий от i-rinat

А где тут UB?

Думал, что тут: «Преобразование в uint16_t тоже определено.»

Забыл, считал, что определено только если оба типа unsigned.

Перечитал: «Otherwise, if the new type is unsigned, the value is converted by repeatedly adding orsubtracting one more than the maximum value that can be represented in the new type until the value is in the range of the new type.»

Deleted
()
Ответ на: комментарий от Deleted

Ещё эпичнее было в досовском x-com'е когда суперпрокаченный боец с силой 255 после очередного повышения становился хлюпиком не способным поднять не то чтобы пистолет, но даже обойму для него. =)

cPunk ★★
()
Ответ на: комментарий от i-rinat

Вот так в следующий раз что-нибудь скажу с умным видом, а в тему заглянет Iron_Bug и раскатает меня по стенкам.

Deleted
()

Был классный справочник по языку Си за авторством Болски. Такая тоненькая синяя книжечка, чтобы можно было в карман положить. Так там был специальный раздел про написание переносимых приложений и связанные с этим типичные ошибки программистов. Рекомендую!

dave ★★★★★
()

Некоторые компиляторы ловят такое во время исполнения и сильно ругаются

vromanov ★★★
()

У меня счётчики миллисекунд так и работают. И проблем нет! Пока это не UB, можно не париться!!!

anonymous
()
$ gcc test.c -o test
test.c: В функции «main»:
test.c:5:16: предупреждение: неявная декларация функции «atoi» [-Wimplicit-function-declaration]
   uint16_t a = atoi(argv[1]);
                ^~~~
$ ./test 
Ошибка сегментирования
$ uname -a
Linux madpower 4.19.66-gentoo #1 Thu Aug 15 17:21:59 MSK 2019 ppc 7455, altivec supported PowerBook6,1 GNU/Linux
$ 
madcore ★★★★★
()

А тут все вкурсе что бывает при переполении int?

числа переполнившие int попадают в иной,печальный мир и там серо скитаются тихонько стоная. А из нуля вылезают их призрачные модули и мстят программисту :-)

MKuznetsov ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.