У меня есть устаревшая кодовая база, которую мы пытаемся перенести с devtoolset-4
на devtoolset-7
. Я заметил интересное поведение в отношении переполнения целых чисел со знаком (точнее, int64_t
).
Существует фрагмент кода, который используется для обнаружения целочисленного переполнения при умножении большого набора целых чисел:
// a and b are int64_t
int64_t product = a * b;
if (b != 0 && product / b != a) {
// Overflow
}
Этот код отлично работал с devtoolset-4. Однако с devtoolset-7 переполнение никогда не обнаруживается.
Например: когда a = 83802282034166
и b = 98765432
, product
становится -5819501405344925872
(очевидно, что значение переполнено).
Но product / b
приводит к значению, равному a (83802282034166)
. Следовательно, условие if
никогда не становится истинным. Его значение должно было быть вычислено на основе переполненного (отрицательного) значения product
: -5819501405344925872 / 98765432 = -58922451788
Как ни странно, математика верна, но вызывает аномальное поведение в отношении devtoolset-4.
- Может ли компилятор кэшировать значение (а не переоценивать его), что приводит к такому поведению?
- Или оптимизация компилятора преобразует оператор
product / b != a
вproduct != a * b
и достигает того же значения переполнения (или, может быть, просто пропускает вычисления на основе приведенного выше оператора, гдеproduct = a * b
)?
Я понимаю, что переполнение целого числа со знаком является «неопределенным поведением» в C++, поэтому поведение компилятора может меняться в разных реализациях. Но может ли кто-нибудь помочь мне понять вышеописанное поведение?
Примечание: версии g++ в devtoolset-4 и devtoolset-7 — g++ (GCC) 5.2
и g++ (GCC) 7.2.1
соответственно.
signed
целочисленное переполнение не определено в С++. Вы не можете надежно обнаружить это постфактум, так как вы неявно находитесь в неопределенном поведении. - person François Andrieux   schedule 28.03.2018if (std::numeric_limits<std::int64_t>::max() / b < a) { /* error */ }
. - person Pete Becker   schedule 28.03.2018product == a * b
, поэтомуproduct / b != a
можно оптимизировать до ->a * b / b != a
->a * 1 != a
->a != a
->false
. - person eerorika   schedule 28.03.2018