TGViewer
Грокаем C++ Грокаем C++ @grokaemcpp · 9.35K subscribers
Post #447 4.76K
​​Проверяем на целочисленное переполнение

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

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

Какие вообще бывают переполнения по типу операции? Если мы складываем 2 числа, то их результат может не влезать в нужное количество разрядов. Вычитание тоже может привести к переполнению, если оба числа будут сильно негативные(не будьте, как эти числа). Умножение тоже, очевидно, может привести к overflow. А вот деление не может. Целые числа у нас не могут быть по модулю меньше единицы, поэтому деление всегда неувеличивает модуль делимого. Значит и переполнится оно не может.

И какая радость, что популярные компиляторы GCC и Clang уже за нас сделали готовые функции, которые могут проверять на signed integer overflow!

bool __builtin_add_overflow(type1 a, type2 b, type3 *res);
bool __builtin_sub_overflow(type1 a, type2 b, type3 *res);
bool __builtin_mul_overflow(type1 a, type2 b, type3 *res);


Они возвращают false, если операция проведена штатно, и true, если было переполнение. Типы type1, type2 и type3 должны быть интегральными типами.

Пользоваться функциями очень просто. Допустим мы решаем стандартную задачку по перевороту инта. То есть из 123 нужно получить 321, из 7493 - 3947, и тд. Задачка плевая, но есть загвоздка. Не любое число можно так перевернуть. Модуль максимального инта ограничивается двумя миллиадрами с копейками. Если у входного значения будут заняты все разряды и на конце будет 9, то перевернутое число уже не влезет в инт. Такие события хотелось бы детектировать и возвращать в этом случае фигу.

std::optional<int32_t> decimal_reverse(int32_t value) {
int32_t result{};
while (value) {
if (__builtin_mul_overflow(result, 10, &result) or
__builtin_add_overflow(result, value % 10, &result))
return std::nullopt;
value /= 10;
}
return result;
}

int main() {
if (decimal_reverse(1234567891).has_value()) {
std::cout << decimal_reverse(1234567891).value() << std::endl;
} else {
std::cout << "Reversing cannot be perform due overflow" << std::endl;
}

if (decimal_reverse(1234567894).has_value()) {
std::cout << decimal_reverse(1234567894).value() << std::endl;
} else {
std::cout << "Reversing cannot be perform due overflow" << std::endl;
}
}

// OUTPUT:
// 1987654321
// Reversing cannot be perform due overflow


Use ready-made solutions. Stay cool.

#cppcore #compiler
  • 🔥 19
  • 👍 11
  • ❤‍🔥 5
  • ❤ 4
  • 🤪 3
More from @grokaemcpp
  1. Oct 14, 2026​​Что внутри std::condition_variable? #опытным Более менее все знакомы с примитивом синхро…
  2. Oct 12, 2026​​WAT #новичкам Как вы думаете, результат выражения: bool math = -1 < 1U; будет правдой ил…
  3. Oct 8, 2026​​Strict weak ordering #опытным На первый взгляд, всё выглядит рабочим: мы создаём 40 зака…
  4. Oct 7, 2026​​Где-то баг... #опытным Вот вам код: struct Order { int price; int id; }; int main() { st…
  5. Oct 5, 2026Откуда spurious wakeup на кондваре? #опытным У кондваров есть метод std::condition_variabl…
  6. Oct 1, 2026​​Stacktrace. Tips #опытным Чтобы полноценно работать со стандартными трейсами, нужно знат…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →