Подтвердить что ты не робот

Насколько катастрофическим является переполнение целых чисел в С++?

Мне просто интересно, как на самом деле происходит катастрофическое переполнение целого числа. Возьмите следующую примерную программу:

#include <iostream>

int main()
{
    int a = 46341;
    int b = a * a;
    std::cout << "hello world\n";
}

Так как a * a переполняется на 32-битных платформах и триггеры переполнения целых чисел undefined, есть ли у меня какие-либо гарантии, что hello world действительно появится на моем экране?


Я удалил "подписанную" часть из моего вопроса на основе следующих стандартных котировок:

(§5/5 С++ 03, §5/4 С++ 11) Если во время оценки выражения результат не определяется математически или нет в диапазоне представляемых значений для его типа, поведение undefined.

(§3.9.1/4) Беззнаковые целые числа, объявленные unsigned, должны подчиняться законам арифметики по модулю 2 ^ n, где n - количество бит в представлении значений этого конкретного размера целого числа. Это означает, что беззнаковая арифметика не переполняет, потому что результат, который не может быть представлен результирующим беззнаковым целым типом, уменьшается по модулю число, которое больше одного наибольшего значения, которое может быть представлено полученным целым без знака тип.

4b9b3361

Ответ 1

Как отмечалось в комментариях @Xeo (я фактически поднял его в чате С++):
Undefined поведение действительно означает его, и оно может поразить вас, когда вы меньше всего этого ожидаете.

Лучший пример этого: Почему целостное переполнение на x86 с GCC вызывает бесконечный цикл?

В x86, целочисленное переполнение целых чисел - это просто обертка. Поэтому обычно вы ожидаете, что то же самое произойдет на C или С++. Однако компилятор может вмешиваться - и использовать поведение undefined как возможность оптимизировать.

В примере, взятом из этого вопроса:

#include <iostream>
using namespace std;

int main(){
    int i = 0x10000000;

    int c = 0;
    do{
        c++;
        i += i;
        cout << i << endl;
    }while (i > 0);

    cout << c << endl;
    return 0;
}

При компиляции с GCC GCC оптимизирует цикл теста и делает это бесконечным циклом.

Ответ 2

Вы можете вызвать некоторые функции безопасности оборудования. Так что нет, у вас нет никакой гарантии.

Изменить: Обратите внимание, что gcc имеет параметр -ftrapv (но он не работает для меня).

Ответ 3

Существует два представления о поведении undefined. Существует мнение, что он собирается собираться для странного оборудования и других особых случаев, но обычно это должно вести себя здорово. И есть мнение, что все может случиться. И в зависимости от источника UB, некоторые придерживаются разных мнений.

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

Итак, когда вы видите поведение undefined, предположите, что что-то может произойти, как бы ни было разумно данное поведение.