Ich verstehe nicht ganz, warum ich keine Ausnahme durch Null bekomme:
int d = 0;
d /= d;
Ich erwartete aber stattdessen eine Division durch Null-Ausnahme d == 1
.
Warum wird keine d /= d
Ausnahme durch Division durch Null ausgelöst, wenn d == 0
?
c++
compiler-optimization
undefined-behavior
division
divide-by-zero
Valerii Boldakov
quelle
quelle
throw
Anweisung ausgelöst . Nichts anderes (es sei denn, Sie befinden sich in einem Land mit undefiniertem Verhalten).Antworten:
C ++ hat keine "Division by Zero" -Ausnahme zu fangen. Das beobachtete Verhalten ist das Ergebnis von Compiler-Optimierungen:
d == 0
) nicht erfüllt sein dürfen , da undefiniertes Verhalten nicht auftrittd / d
muss immer gleich 1 sein.Jedoch...
Wir können den Compiler zwingen, eine "echte" Division durch Null mit einer geringfügigen Änderung Ihres Codes auszulösen.
volatile int d = 0; d /= d; //What happens?
Nun bleibt die Frage: Nun, da wir den Compiler grundsätzlich gezwungen haben, dies zuzulassen, was passiert dann? Es ist undefiniertes Verhalten - aber wir haben jetzt verhindert, dass der Compiler dieses undefinierte Verhalten optimiert.
Meistens hängt es von der Zielumgebung ab. Dies löst keine Software-Ausnahme aus, kann jedoch (abhängig von der Ziel-CPU) eine Hardware-Ausnahme (eine Ganzzahl-Division durch Null) auslösen, die nicht auf herkömmliche Weise abgefangen werden kann, wenn eine Software-Ausnahme abgefangen werden kann. Dies ist definitiv der Fall für eine x86-CPU und die meisten anderen (aber nicht alle!) Architekturen.
Es gibt jedoch Methoden, um mit der Hardware-Ausnahme umzugehen (falls sie auftritt), anstatt nur das Programm abstürzen zu lassen: In diesem Beitrag finden Sie einige Methoden, die möglicherweise anwendbar sind: Ausnahme abfangen: durch Null teilen . Beachten Sie, dass sie von Compiler zu Compiler unterschiedlich sind.
quelle
1
eine vollkommen gültige Sache ist. Das Erhalten von 14684554 muss daran liegen, dass der Compiler noch weiter optimiert - er verbreitet die Anfangsbedingungd==0
und kann daher nicht nur auf "dies ist entweder 1 oder UB" schließen, sondern tatsächlich auf "dies ist UB, Punkt". Daher macht es sich nicht einmal die Mühe, Code zu erzeugen, der die Konstante lädt1
.Um die anderen Antworten zu ergänzen, bedeutet die Tatsache, dass die Division durch Null ein undefiniertes Verhalten ist, dass der Compiler in den Fällen, in denen dies passieren würde, alles tun kann :
0 / 0 == 1
und entsprechend optimieren. Genau das scheint es hier getan zu haben.0 / 0 == 42
undd
auf diesen Wert setzen.d
unbestimmt ist, und so die Variable nicht initialisieren, so dass ihr Wert der Wert ist, der zuvor in den ihm zugewiesenen Speicher geschrieben wurde. Einige der unerwarteten Werte, die bei anderen Compilern in den Kommentaren beobachtet wurden, können durch diese Compiler verursacht werden, die so etwas tun.d
zum Zeitpunkt der Kompilierung nicht bekannt war, könnte der Compiler dennoch annehmen, dass er niemals Null ist, und den Code entsprechend optimieren. Im speziellen Fall des OP-Codes ist dies praktisch nicht von dem Compiler zu unterscheiden, der dies nur annimmt0 / 0 == 1
, aber der Compiler könnte beispielsweise auch annehmen, dass dasputs()
Inif (d == 0) puts("About to divide by zero!"); d /= d;
niemals ausgeführt wird!quelle
Das Verhalten der Ganzzahldivision durch Null ist vom C ++ - Standard nicht definiert. Es ist nicht erforderlich, eine Ausnahme auszulösen.
(Die Gleitkommadivision durch Null ist ebenfalls undefiniert, wird jedoch von IEEE754 definiert.)
Ihr Compiler optimiert
d /= d
effektiv,d = 1
was eine vernünftige Wahl ist. Diese Optimierung ist zulässig, da davon ausgegangen werden darf, dass Ihr Code kein undefiniertes Verhalten enthält - dasd
kann unmöglich Null sein.quelle
d
unmöglich Null sein kann", nehmen Sie auch an, dass der Compiler die Zeile nicht sieht:int d = 0;
?? :)Beachten Sie, dass Ihr Code in diesem (und anderen Fällen) eine C ++ - Ausnahme generieren kann, indem Sie Boost-sichere Zahlen verwenden. https://github.com/boostorg/safe_numerics
quelle