Ist die unbewertete Division durch 0 undefiniertes Verhalten?

Lesezeit: 5 Minuten

Benutzeravatar von Luchian Grigore
Luchian Grigore

Ich habe eine Meinungsverschiedenheit mit einigen Kollegen über den folgenden Code:

int foo ( int a, int b )
{
    return b > 0 ? a / b : a;
}

Zeigt dieser Code undefiniertes Verhalten?

BEARBEITEN: Die Meinungsverschiedenheit begann mit einem Fehler in einem übermäßig eifrigen optimierenden Compiler, bei dem die b > 0 Check wurde optimiert.

  • Gibt es einen Grund zu der Annahme, dass dies der Fall ist?

    – Juanchopanza

    21. Oktober 2016 um 9:14 Uhr

  • Ich meine, es ist nur UB, wenn Sie eine Division durch 0 ausführen. Sie tun es hier nicht.

    – Heut

    21. Oktober 2016 um 9:14 Uhr

  • @LuchianGrigore Ich denke, sein Punkt war, wenn Ihre Mitarbeiter (oder Sie) die Position einnehmen, die UB zeigt, vielleicht der Grund dafür warum Sie (oder Sie) denken, dass dies eine würdige Ergänzung zu Ihrer Frage wäre.

    – WhozCraig

    21. Oktober 2016 um 9:21 Uhr


  • Häh? Ist ist return p ? p->flag_value : false UB wann p ist Null? Nein. Alle Code wäre kaputt, wenn das der Fall wäre.

    – Kerrek SB

    21. Oktober 2016 um 9:37 Uhr

  • Es wäre auch UB, wenn die Operation einen Überlauf erzeugt. Aber für eine ganzzahlige Division kann das nur passieren, wenn Sie INT_MIN durch -1 teilen, und der Wächter (b>0) vermeidet auch diesen Fall.

    – Hans Olsson

    21. Oktober 2016 um 14:11 Uhr

Benutzeravatar von krzaq
krzaq

Nein.


Zitate aus N4140:

§5.16 [expr.cond]/1

Bedingte Ausdrücke werden von rechts nach links gruppiert. Der erste Ausdruck wird kontextbezogen in bool konvertiert. Es wird ausgewertet und wenn es wahr ist, ist das Ergebnis des Bedingungsausdrucks der Wert des zweiten Ausdrucks, andernfalls der des dritten Ausdrucks. Nur einer der
zweiter und dritter Ausdruck wird ausgewertet.

Des Weiteren:

§5 [expr]/4

Wenn während der Auswertung eines Ausdrucks das Ergebnis nicht mathematisch definiert ist oder nicht im Bereich darstellbarer Werte für seinen Typ liegt, ist das Verhalten undefiniert.

Dies geschieht hier eindeutig nicht. Der gleiche Absatz erwähnt die Division durch Null explizit in einer Notiz, und obwohl es nicht normativ ist, macht es noch deutlicher, dass es für diese Situation relevant ist:

[ Note: most existing implementations of C++ ignore integer overflows.
Treatment of division by zero, forming a remainder using a zero
divisor, and all floating point exceptions vary among machines, and is
usually adjustable by a library function. —end note ]


Es gibt auch Indizienbeweise, die den obigen Punkt bekräftigen: Der Bedingungsoperator wird verwendet, um das Verhalten bedingt undefiniert zu machen.

§8.5 [dcl.init]/12.3

int f(bool b) {
  unsigned char c;
  unsigned char d = c; // OK, d has an indeterminate value
  int e = d; // undefined behavior
  return b ? d : 0; // undefined behavior if b is true
}

Im obigen Beispiel mit d zu initialisieren int (oder etwas anderes als unsigned char) ist nicht definiert. Es wird jedoch klar gesagt, dass der UB nur auftritt, wenn der UB-Zweig ausgewertet wird.


Aus der sprachjuristischen Perspektive heraus: Wenn dies UB sein könnte, könnte jede Division als UB behandelt werden, da der Divisor möglicherweise 0 sein könnte. Dies ist nicht der Sinn der Regel.

  • @LuchianGrigore Die Essenz der Antwort auf Ihre Frage liegt vollständig im kursiv gedruckten Satz (Nur einer der zweiten und dritten Ausdrücke wird ausgewertet). Wenn jemand diese Eigenschaft der bedingten Operation nicht versteht, kann er viele weitere Fragen wie Ihre generieren, bei denen die Division durch Null durch die Dereferenzierung eines Nullzeigers ersetzt wird, Zugriff außerhalb der Grenzen, ein erwarteter, aber nicht beobachteter wichtiger Nebeneffekt , etc.

    – Leon

    21. Oktober 2016 um 10:16 Uhr

  • -1: Die Frage (wie im Titel geschrieben) fragt nicht, ob die Teilung bewertet wird – sie fragt, ob die Teilung UB sein kann, obwohl sie nicht bewertet wird.

    – Benutzer253751

    22. Oktober 2016 um 13:23 Uhr


  • @immibis tut es, siehe Kommentar von Leon.

    – Ruslan

    22. Oktober 2016 um 14:13 Uhr

  • @immibis Aus dem zweiten Zitat in der Antwort folgt: Der Grund, warum die Division durch Null UB ist, liegt daran §5 [expr]/4. Beachten Sie die Worte „während der Auswertung eines Ausdrucks” und “mathematisch definiert”. Das erste Zitat gibt an, wann der “nicht mathematisch definierte” Ausdruck ausgewertet wird, also: nie.

    – Millenniumbug

    22. Oktober 2016 um 15:05 Uhr


  • @jdm Ich nehme an, Sie beziehen sich auf Raymond Chens Artikel, wenn Sie von Zeitreisen sprechen. Sie werden feststellen, dass das Problem dort darin besteht, dass der UB vor der Prüfung aufgerufen wird. Ein Analogon wäre hier cout << "a/b: " << a/b << endl; return b != 0 ? a / b : a;.

    – krzaq

    23. Oktober 2016 um 16:57 Uhr

Benutzeravatar von glauxosdever
glauxosdever

Im Beispielcode gibt es keine Möglichkeit, durch Null zu dividieren. Wenn der Prozessor ausgeführt wird a / bdas hat er schon geprüft b > 0deshalb b ist ungleich Null.

Zu beachten ist, dass ggf a == INT_MIN und b == -1dann a/b ist auch undefiniertes Verhalten. Dies wird aber trotzdem verhindert, da die Bedingung to auswertet false In diesem Fall.

Obwohl ich nicht sicher bin, ob du das gemeint hast return b != 0 ? a / b : a; und nicht return b > 0 ? a / b : a; Wenn b kleiner als Null ist, ist die Division immer noch gültig, es sei denn, es handelt sich um die oben beschriebene Bedingung.

  • Hans Olsen weist auf einen Fall hin a / b kann für negativ immer noch undefiniert sein b in den Kommentaren.

    – chepner

    21. Oktober 2016 um 14:42 Uhr


Zeigt dieser Code undefiniertes Verhalten?

Nein. Tut es nicht. Der Ausdruck

return b > 0 ? a / b : a;  

ist äquivalent zu

if(b > 0)
    return a/b;     // this will be executed only when b is greater than 0
else
    return a;  

Division nur durchgeführt, wenn b ist größer als 0.

  • -1: Die Frage (wie im Titel geschrieben) fragt nicht, ob die Teilung bewertet wird – sie fragt, ob die Teilung UB sein kann, obwohl sie nicht bewertet wird.

    – Benutzer253751

    22. Oktober 2016 um 13:24 Uhr

  • @immibis; Die Frage (wie im Titel geschrieben) fragt nicht, ob die Division bewertet wird: wahr, aber die Antwort liegt in der Auswertung des Divisionsausdrucks. Hier gibt es keine Division durch Null.

    – Hacken

    22. Oktober 2016 um 13:38 Uhr


  • Es ist eine Aussage, kein Ausdruck.

    – Leuschenko

    22. Oktober 2016 um 15:48 Uhr

  • @ Leuschenko; a/b ist ein Ausdruck.

    – Hacken

    22. Oktober 2016 um 16:00 Uhr

Wenn dies UB wäre, dann wäre es das auch

if(a != null && *a == 42)
{
 .....
}

Und die Abfolge von ifs , ands und ors ist eindeutig darauf ausgelegt, diese Art von Konstrukt ausdrücklich zuzulassen. Ich kann mir nicht vorstellen, dass Ihre Kollegen dem widersprechen würden

1413660cookie-checkIst die unbewertete Division durch 0 undefiniertes Verhalten?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy