Ответ вслух Senior Типы и неопределённое поведение обновлено

Как безопасно проверить переполнение

Вопрос

Как проверить, что a + b или a * b для std::int64_t не переполнится? Расскажите несколько способов и их плюсы и минусы.

Попробуйте сами

Ответьте вслух за 2 минуты, как на собесе. Потом сверьтесь с тезисами: что прозвучало, а что нет.

Показать ответ и разбор

Коротко

Главное правило: проверять нужно до операции, потому что само переполнение знакового уже UB, и проверка вида a + b < a может быть удалена оптимизатором. Для сложения переносимо так: если b 0, переполнение будет при a INT64MAX − b, если b < 0, при a < INT64MIN − b.

Что должно прозвучать в ответе

  • Проверка до операции: `b > 0 && a > MAX - b` и аналог для отрицательных

  • Встроенные функции `__builtin_add_overflow`, `__builtin_mul_overflow` в GCC и Clang

  • Вычисление в более широком типе (`__int128`) и сравнение с границами

  • Нельзя проверять после операции: переполнение уже UB

  • Для умножения проверка делением: `a > MAX / b` с аккуратной обработкой знаков

Что могут спросить следом

  • Почему if (a + b < a) неправильная проверка?
  • Что выбрать в переносимом коде без расширений GCC?

Разбор

Главное правило: проверять нужно до операции, потому что само переполнение знакового уже UB, и проверка вида a + b < a может быть удалена оптимизатором. Для сложения переносимо так: если b > 0, переполнение будет при a > INT64_MAX − b, если b < 0, при a < INT64_MIN − b. Для умножения аналогично через деление, но там много случаев со знаками и с −1 · INT64_MIN. На GCC и Clang удобнее встроенные функции __builtin_add_overflow(a, b, &res) и __builtin_mul_overflow: они возвращают флаг и компилируются в инструкцию с проверкой флага переполнения, это быстро и без ошибок. Третий вариант: посчитать в более широком типе, для 64 бит это __int128, и сравнить с границами. Он простой, но тоже не стандартный. В переносимом коде я бы обернул проверку в функцию с предусловиями и покрыл тестами на границах, а в коде под GCC и Clang использовал встроенные функции.

Ответьте сами, а не прочитайте

В тренажёре вопрос попадёт в повторения и вернётся, когда начнёт забываться. Плюс билеты с зачётом: 20 вопросов, не больше 2 ошибок.