Я не совсем понимаю, почему я не получаю деление на ноль исключений:
int d = 0;
d /= d;
Я ожидал получить деление на ноль исключений, но вместо этого d == 1
.
Почему d /= d
не создает исключение деления на ноль, когда d == 0
?
Я не совсем понимаю, почему я не получаю деление на ноль исключений:
int d = 0;
d /= d;
Я ожидал получить деление на ноль исключений, но вместо этого d == 1
.
Почему d /= d
не создает исключение деления на ноль, когда d == 0
?
C++ не имеет исключения "деление на ноль". Поведение, которое вы наблюдаете, является результатом оптимизации компилятора:
d == 0
) не должны выполнятьсяd / d
всегда должен быть равен 1.Мы можем заставить компилятор вызвать "реальное" деление на ноль с небольшим изменением кода.
volatile int d = 0;
d /= d; //What happens?
Итак, теперь остается вопрос: теперь, когда мы в основном заставили компилятор позволить этому случиться, что происходит? Это неопределенное поведение, но теперь мы не позволяем компилятору оптимизировать это неопределенное поведение.
Главным образом, это зависит от целевой среды. Это не вызовет программную исключительную ситуацию, но может (в зависимости от целевого ЦП) вызвать аппаратную исключительную ситуацию (целочисленное деление на ноль), которая не может быть перехвачена традиционным способом, которым может быть обработана программная исключительная ситуация. Это определенно относится к процессору x86 и большинству других (но не всех!) Архитектур.
Однако существуют способы борьбы с аппаратным исключением (если оно происходит), а не просто сбоем программы: посмотрите в этом посте некоторые методы, которые могут быть применимы: Перехват исключения: деление на ноль. Обратите внимание, что они варьируются от компилятора к компилятору.
В дополнение к другим ответам тот факт, что деление на ноль является неопределенным поведением, означает, что компилятор может делать все, что угодно:
0 / 0 == 1
и оптимизировать соответственно. Это эффективно то, что, похоже, здесь и сделано.0 / 0 == 42
и установить d
на это значение.d
является неопределенным, и, таким образом, оставить переменную неинициализированной, так что ее значение будет таким, каким оно было ранее записано в выделенную для него память. Некоторые неожиданные значения, наблюдаемые в других компиляторах в комментариях, могут быть вызваны тем, что эти компиляторы делают что-то подобное.d
не было известно во время компиляции, компилятор все равно мог предположить, что оно никогда не обнулялось, и соответствующим образом оптимизировать код. В частном случае кода OP это фактически неотличимо от компилятора, только если предположить, что 0 / 0 == 1
, но компилятор также может, например, предположить, что puts()
в if (d == 0) puts("About to divide by zero!"); d /= d;
никогда не будет выполнен!Поведение целочисленного деления на ноль не определено стандартом C++. not не требуется для создания исключения.
(Деление с плавающей точкой на ноль также не определено, но IEEE754 определяет его.)
Ваш компилятор оптимизирует d /= d
для эффективного d = 1
, что является разумным выбором. Это позволило выполнить эту оптимизацию, поскольку позволило предположить, что в вашем коде нет неопределенного поведения - то есть d
не может быть нулем.
Обратите внимание, что в этом (и других случаях) ваш код может генерировать исключение C++, используя числовые значения повышения безопасности. https://github.com/boostorg/safe_numerics