No entiendo muy bien por qué no obtengo una excepción de división por cero:
int d = 0;
d /= d;
Esperaba obtener una división por excepción cero, pero en cambio d == 1
.
¿Por qué no d /= d
lanza una excepción de división por cero cuando d == 0
?
c++
compiler-optimization
undefined-behavior
division
divide-by-zero
Valerii Boldakov
fuente
fuente
throw
declaración. Nada más (a menos que estés en una tierra de comportamiento indefinido).Respuestas:
C ++ no tiene una excepción de "División por cero" para detectar. El comportamiento que está observando es el resultado de las optimizaciones del compilador:
d == 0
) no deben ocurrir.d / d
siempre debe ser igual a 1.Sin embargo...
Podemos forzar al compilador a activar una división "real" por cero con un pequeño ajuste a su código.
volatile int d = 0; d /= d; //What happens?
Así que ahora la pregunta sigue siendo: ahora que básicamente hemos forzado al compilador a permitir que esto suceda, ¿qué sucede? Es un comportamiento indefinido, pero ahora hemos evitado que el compilador optimice este comportamiento indefinido.
Principalmente, depende del entorno de destino. Esto no activará una excepción de software, pero puede (dependiendo de la CPU de destino) activar una excepción de hardware (un entero-dividir por cero), que no se puede detectar de la manera tradicional. Este es definitivamente el caso de una CPU x86 y la mayoría de las otras arquitecturas (¡pero no todas!).
Sin embargo, existen métodos para lidiar con la excepción de hardware (si ocurre) en lugar de simplemente dejar que el programa se bloquee: mire esta publicación para ver algunos métodos que podrían ser aplicables: Captura de excepción: dividir por cero . Tenga en cuenta que varían de un compilador a otro.
fuente
1
es algo perfectamente válido. Obtener 14684554 debe ser porque el compilador optimiza aún más - propaga lad==0
condición inicial y por lo tanto puede concluir no solo "esto es 1 o UB" sino que de hecho "esto es UB, punto". Por lo tanto, ni siquiera se molesta en producir código que cargue la constante1
.Solo para complementar las otras respuestas, el hecho de que la división por cero sea un comportamiento indefinido significa que el compilador es libre de hacer cualquier cosa en los casos en que suceda:
0 / 0 == 1
y optimizar en consecuencia. Eso es efectivamente lo que parece haber hecho aquí.0 / 0 == 42
y establecerd
ese valor.d
es indeterminado y, por lo tanto, dejar la variable sin inicializar, de modo que su valor sea lo que haya sido escrito previamente en la memoria asignada. Algunos de los valores inesperados observados en otros compiladores en los comentarios pueden ser causados por esos compiladores que hacen algo como esto.d
no se conocía el valor original de en el momento de la compilación, el compilador aún podría asumir que nunca es cero y optimizar el código en consecuencia. En el caso particular del código de OP, esto es efectivamente indistinguible del compilador simplemente asumiendo eso0 / 0 == 1
, pero el compilador también podría, por ejemplo, asumir que elputs()
inif (d == 0) puts("About to divide by zero!"); d /= d;
nunca se ejecuta.fuente
El comportamiento de la división de enteros por cero no está definido por el estándar C ++. Se no se requiere para producir una excepción.
(La división de coma flotante por cero también está indefinida, pero IEEE754 la define).
Su compilador se está optimizando
d /= d
, efectivamente, lod = 1
cual es una elección razonable. Se le permite realizar esta optimización ya que se le permite asumir que no hay un comportamiento indefinido en su código, qued
no puede ser cero.fuente
d
no puede ser cero", ¿también asume que el compilador no ve la línea:int d = 0;
?? :)Tenga en cuenta que puede hacer que su código genere una excepción de C ++ en este (y otros casos) mediante el uso de números seguros de refuerzo. https://github.com/boostorg/safe_numerics
fuente