Was genau bedeuten "IB" und "UB"?

110

Ich habe die Begriffe "IB" und "UB" mehrmals gesehen, insbesondere im Zusammenhang mit C ++. Ich habe versucht, sie zu googeln, aber anscheinend werden diese Zwei-Buchstaben-Kombinationen häufig verwendet. : P.

Also, ich frage dich ... was meinen sie, wenn sie gesagt werden, als wären sie eine schlechte Sache?

cHao
quelle
5
Wenn Sie die Änderungen anderer zurücksetzen möchten, stellen Sie bitte sicher, dass Rechtschreibung, Zeichensetzung und Grammatik perfekt sind. Das Zurücksetzen von Änderungen, die eine wesentliche Verbesserung gegenüber dem Originaltext darstellen, ist sinnlos.
Robert Harvey

Antworten:

139

IB: Implementierungsdefiniertes Verhalten. Der Standard überlässt es dem jeweiligen Compiler / der jeweiligen Plattform, das genaue Verhalten zu definieren, verlangt jedoch, dass es definiert wird.

Die Verwendung eines implementierungsdefinierten Verhaltens kann nützlich sein, macht Ihren Code jedoch weniger portabel.

UB: Undefiniertes Verhalten. Der Standard legt nicht fest, wie sich ein Programm, das undefiniertes Verhalten aufruft, verhalten soll. Auch als "Nasendämonen" bekannt, da theoretisch Dämonen aus der Nase fliegen könnten.

Die Verwendung von undefiniertem Verhalten ist fast immer eine schlechte Idee. Selbst wenn es manchmal zu funktionieren scheint, kann jede Änderung an Umgebung, Compiler oder Plattform Ihren Code zufällig beschädigen.

Thomas
quelle
11
Ich warte immer noch auf einen Dämon, der jemandem aus der Nase fliegt, weil er in C ++ undefiniertes Verhalten verwendet. Ich denke, es wird passieren, wenn die ersten Compiler den neuen C ++ - Standard vollständig erfüllen.
OregonGhost
4
@OregonGhost: Ich denke du hast recht. Ich habe es ein paar Mal mit Einhörnern gesehen, aber niemals mit Dämonen.
Thomas
33
@OregonGhost - Der Standard gibt nicht an, wie viele Hörner ein Dämon haben soll.
DVK
5
@ Michael Burr: Ich bevorzuge "Feuer fangen". Es ist offensichtlich katastrophal und zumindest vage plausibel (Computerhardware gerät manchmal in Brand, zugegebenermaßen aus Gründen der Hardware und nicht aufgrund eines Softwarefehlers bei einem System, auf dem Sie diesen Thread lesen würden).
Steve Jessop
1
Es ist lustig, wie niemand, der diese Frage beantwortet hat, weniger Ansehen hat als 30.000.
19

Implementierungsdefiniertes Verhalten und undefiniertes Verhalten

Der C ++ - Standard ist sehr spezifisch in Bezug auf die Auswirkungen verschiedener Konstrukte, und insbesondere sollten Sie sich immer dieser Kategorien von Problemen bewusst sein :

  • Undefiniertes Verhalten bedeutet, dass absolut keine Garantien gegeben werden. Der Code könnte funktionieren oder Ihre Festplatte in Brand setzen oder Dämonen aus Ihrer Nase fliegen lassen . In Bezug auf die C ++ - Sprache kann absolut alles passieren. In der Praxis bedeutet dies im Allgemeinen, dass Sie einen nicht behebbaren Fehler haben. Wenn dies geschieht, kann man nicht vertrauen wirklich etwas über Ihre Bewerbung (weil eine der Auswirkungen dieser undefinierten Verhalten könnte nur zu Chaos gewesen Speicher durch den Rest Ihrer App verwendet wird ). Es muss nicht konsistent sein, daher kann das zweimalige Ausführen des Programms zu unterschiedlichen Ergebnissen führen. Dies kann von den Mondphasen, der Farbe des Hemdes, das Sie tragen, oder absolut allem anderen abhängen.

  • Nicht spezifiziertes Verhalten bedeutet, dass das Programm etwas Vernünftiges und Konsistentes tun muss, dies muss jedoch nicht dokumentiert werden .

  • Das implementierungsdefinierte Verhalten ähnelt dem nicht angegebenen, muss jedoch auch von den Compiler-Autoren dokumentiert werden. Ein Beispiel hierfür ist das Ergebnis von a reinterpret_cast. in der Regel , ändert er einfach den Typ eines Zeigers, ohne die Adresse zu ändern, aber die Abbildung tatsächlich die Implementierung definiert, so dass ein Compiler könnte auf eine ganz andere Adresse zuordnen, solange sie diese Wahl dokumentiert. Ein weiteres Beispiel ist die Größe eines Int. Dem C ++ - Standard ist es egal, ob es 2, 4 oder 8 Bytes sind, aber er muss vom Compiler dokumentiert werden

Allen gemeinsam ist jedoch, dass sie am besten vermieden werden. Halten Sie sich nach Möglichkeit an ein Verhalten, das zu 100% im C ++ - Standard selbst festgelegt ist. Auf diese Weise ist Ihnen die Portabilität garantiert.

Oft müssen Sie sich auch auf ein implementierungsdefiniertes Verhalten verlassen. Es mag unvermeidlich sein, aber Sie sollten trotzdem darauf achten und sich bewusst sein, dass Sie sich auf etwas verlassen, das sich zwischen verschiedenen Compilern ändern kann.

Undefiniertes Verhalten sollte dagegen immer vermieden werden. Im Allgemeinen sollten Sie einfach davon ausgehen, dass Ihr Programm auf die eine oder andere Weise explodiert.

jalf
quelle
1
UB sollte vermieden werden, wenn Sie Wert auf Portabilität legen . Eine bestimmte Implementierung kann definieren, was für ein bestimmtes undefiniertes Verhalten geschieht. In einigen Fällen (insbesondere bei Gerätetreibern und kleineren eingebetteten Systemen) müssen Sie diese Dinge verwenden.
Jerry Coffin
3
@ Jerry: Nein, UB sollte vermieden werden, wenn es völlig undefiniert ist . Wenn die Plattform / Implementierung / Laufzeit / Compiler weitere Garantien bietet, können Sie sich auf das Verhalten verlassen und die Portabilität verlieren. Aber dann ist es nicht mehr ganz so undefiniert ... Meistens haben Sie jedoch keine solchen Garantien, und undefiniert ist nur undefiniert und sollte unter allen Umständen vermieden werden.
Jalf
"konsistent" könnte eine irreführende Beschreibung von nicht spezifiziertem Verhalten sein. Es hat mit dem allgemeinen Kontext der Operation konsistent zu sein, zum Beispiel , wenn ein Ausdruck „nicht spezifizierten Wert“ dann hat , muss das Ergebnis sein ein Wert, wenn Sie speichern es dann der gespeicherte Wert danach gleich vergleichen muss sich, und so weiter. Nicht spezifizierte Ergebnisse müssen jedoch nicht über die Zeit konsistent sein (gleiche Ausgabe für dieselbe Eingabe, wenn Sie sie erneut ausführen) oder sogar deterministisch.
Steve Jessop
"nicht mehr ganz so undefiniert" - es ist genau so undefiniert durch den Standard , und UB ist eine Kurzform, die durch den Standard undefiniert bedeutet. In Ihrem Beispiel wird es durch die Implementierung definiert. In diesem Fall können Sie sich auf ein Verhalten verlassen, das nicht durch den Standard oder die Implementierung definiert ist, wenn Sie den Objektcode überprüft haben und nicht vorhaben, ihn jemals wieder neu zu kompilieren ;-)
Steve Jessop
"muss danach gleich mit sich selbst vergleichen". Hmm, es sei denn, es ist ein NaN. Auf jeden Fall muss es das Verhalten haben, das für seinen Typ erforderlich ist.
Steve Jessop
8
  • IB: Ist das implementierungsdefinierte Verhalten - der Compiler muss dokumentieren, was er tut. >>Ein Beispiel ist die Ausführung einer Operation mit einem negativen Wert.

  • UB: undefiniertes Verhalten - Der Compiler kann alles tun, einschließlich einfach abstürzen oder unvorhersehbare Ergebnisse liefern. Das Dereferenzieren eines Nullzeigers fällt in diese Kategorie, aber auch subtilere Dinge wie Zeigerarithmetik, die außerhalb der Grenzen eines Arrayobjekts liegen.

Ein anderer verwandter Begriff ist "nicht spezifiziertes Verhalten". Dies ist eine Art zwischen implementierungsdefiniertem und undefiniertem Verhalten. Für nicht spezifiziertes Verhalten muss der Compiler etwas gemäß dem Standard tun, aber genau, welche Auswahl der Standard ihm gibt, liegt beim Compiler und muss nicht definiert (oder sogar konsistent) werden. Dinge wie die Reihenfolge der Bewertung von Unterausdrücken fallen in diese Kategorie. Der Compiler kann diese in beliebiger Reihenfolge ausführen und sie in verschiedenen Builds oder sogar in verschiedenen Läufen desselben Builds unterschiedlich ausführen (unwahrscheinlich, aber zulässig).

Michael Burr
quelle
4

Die Kurzversion:

Implementierungsdefiniertes Verhalten (IB): Richtig programmiert, aber unbestimmt *

Undefiniertes Verhalten (UB): Falsch programmiert (dh ein Fehler !)

*) "unbestimmt", was den Sprachstandard betrifft, wird er natürlich auf jeder festen Plattform bestimmt.

Kerrek SB
quelle
Wenn der Standard angibt, dass eine Aktion ein implementierungsdefiniertes Verhalten aufruft, müssen Implementierungen ein konsistentes Verhalten angeben, das sich aus dieser Aktion ergibt. Leider gibt es keine Verhaltenskategorie, für die eine Implementierung erforderlich wäre, um mögliche Konsequenzen anzugeben, aber keine bestimmte Konsequenz konsistent hätte.
Supercat