Я не зовсім розумію, чому я не отримую ділення на нульовий виняток:
int d = 0;
d /= d;
Я очікував отримати ділення на нульовий виняток, але замість цього d == 1
.
Чому не d /= d
викидає ділення на нульовий виняток, коли d == 0
?
Я не зовсім розумію, чому я не отримую ділення на нульовий виняток:
int d = 0;
d /= d;
Я очікував отримати ділення на нульовий виняток, але замість цього d == 1
.
Чому не d /= d
викидає ділення на нульовий виняток, коли d == 0
?
throw
оператором. Нічого іншого (якщо ви не на землі з невизначеною поведінкою).
Відповіді:
C ++ не має винятку "Поділ за нулем", який можна зловити. Поведінка, яку ви спостерігаєте, є результатом оптимізації компілятора:
d == 0
) не повинні відбуватисяd / d
завжди повинен дорівнювати 1.Ми можемо змусити компілятор викликати "справжнє" ділення на нуль з незначним налаштуванням вашого коду.
volatile int d = 0;
d /= d; //What happens?
Отже, зараз залишається питання: що, коли ми в основному змусили компілятор дозволити це, що відбувається? Це невизначена поведінка, але ми тепер завадили компілятору оптимізувати цю невизначену поведінку.
Здебільшого це залежить від цільового середовища. Це не спричинить виняток програмного забезпечення, але може (залежно від цільового процесора) викликати апаратне виняток (ціле число-поділ-нуль), яке традиційно не можна визначити, як можна визначити виняток програмного забезпечення. Це точно стосується процесора x86 та більшості інших (але не всіх!) Архітектур.
Однак існують методи боротьби з апаратним винятком (якщо він трапляється) замість того, щоб просто дозволити програмі завершити роботу: подивіться на цю публікацію деякі методи, які можуть бути застосовні: Ловіть виняток: розділіть на нуль . Зверніть увагу, що вони різняться залежно від компілятора.
1
- це цілком дійсне що завгодно. Отримання 14684554 повинно бути тому, що компілятор оптимізує ще більше - він поширює початкову d==0
умову і, отже, може зробити висновок не лише "це або 1, або UB", а насправді "це UB, точка". Тому навіть не заважає створювати код, який завантажує константу 1
.
Просто доповнюючи інші відповіді, той факт, що ділення на нуль є невизначеною поведінкою, означає, що компілятор може робити що завгодно у випадках, коли це могло статися:
0 / 0 == 1
і відповідно оптимізувати. Це фактично те, що, здається, було зроблено тут.0 / 0 == 42
і встановити d
це значення.d
є невизначеним, і, таким чином, залишити змінну неініціалізованою, так що її значення буде тим, що раніше було записано в виділену для неї пам'ять. Деякі несподівані значення, які спостерігаються для інших компіляторів у коментарях, можуть бути спричинені тими компіляторами, які роблять щось подібне.d
не було відоме під час компіляції, компілятор все одно міг припустити, що воно ніколи не дорівнює нулю, і оптимізувати код відповідно. У приватному випадку коду OP це практично 0 / 0 == 1
неможливо відрізнити від компілятора, просто припускаючи це , але компілятор також може, наприклад, припустити, що puts()
in if (d == 0) puts("About to divide by zero!"); d /= d;
ніколи не виконується!Поведінка цілочисельного ділення на нуль не визначена стандартом С ++. Це не так обов'язково кидати виняток.
(Ділення з плаваючою точкою на нуль також не визначено, але IEEE754 це визначає.)
Ваш компілятор оптимізує d /= d
, ефективно, d = 1
що є розумним вибором. Дозволено робити цю оптимізацію, оскільки дозволяється припускати, що у вашому коді немає невизначеної поведінки - тобто це d
не може бути нулем.
d
не може бути нульовим", ви також вважаєте, що компілятор не бачить рядка: int d = 0;
?? :)
Зверніть увагу, що ви можете дозволити коду генерувати виняток на C ++ у цьому (та інших випадках), використовуючи безпечні цифрові цифри підвищення. https://github.com/boostorg/safe_numerics