2010-05-04 8 views
83

Ich habe die Begriffe "IB" und "UB" mehrmals verwendet, insbesondere im Zusammenhang mit C++. Ich habe versucht, sie zu googeln, aber anscheinend sind diese Zwei-Buchstaben-Kombinationen sehr nützlich. : PWas genau bedeuten "IB" und "UB"?

Also, ich frage Sie ... was bedeuten sie, wenn sie gesagt werden, als ob sie eine schlechte Sache sind?

+3

Wenn Sie sich dafür entscheiden, die Bearbeitungen anderer Personen rückgängig zu machen, stellen Sie bitte sicher, dass Ihre Rechtschreibung, Interpunktion und Grammatik perfekt sind. Rollback-Bearbeitungen, die eine wesentliche Verbesserung gegenüber dem ursprünglichen Text darstellen, sind sinnlos. –

Antwort

102

IB: Implementierung definierten Verhalten. Der Standard überlässt es dem jeweiligen Compiler/der Plattform, das genaue Verhalten zu definieren, erfordert aber, 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 verhalten soll, das undefiniertes Verhalten aufruft. Auch bekannt als "nasale Dämonen", weil es theoretisch Dämonen aus der Nase fliegen lassen könnte.

Die Verwendung von undefiniertem Verhalten ist fast immer eine schlechte Idee. Auch wenn es manchmal zu funktionieren scheint, kann jede Änderung der Umgebung, des Compilers oder der Plattform nach dem Zufallsprinzip Ihren Code beschädigen.

+9

Ich warte immer noch auf einen Dämon, der jemandem aus der Nase fliegt, weil er undefiniertes Verhalten in C++ verwendet. Ich denke, es wird passieren, wenn die ersten Compiler den neuen C++ - Standard vollständig erfüllen. – OregonGhost

+2

+1 für "nasale Dämonen". :) – cHao

+4

@OregonGhost: Ich denke du hast Recht. Ich habe es ein paar Mal mit Einhörnern gesehen, aber niemals Dämonen. – Thomas

8
  • IB: ist implementiertes Verhalten definiert - der Compiler muss dokumentieren, was es tut. Eine >> Operation bei einem negativen Wert ist ein Beispiel.

  • UB: undefiniertes Verhalten - der Compiler kann alles tun, einschließlich Absturz oder unvorhersehbare Ergebnisse. Die Dereferenzierung eines Null-Zeigers fällt in diese Kategorie, aber auch subtilere Dinge wie Zeigerarithmetik, die außerhalb der Grenzen eines Array-Objekts liegt.

Ein anderer verwandter Begriff ist "nicht spezifiziertes Verhalten". Dies ist eine Art zwischen implementierter und nicht definierter Verhaltensweise. Für nicht spezifiziertes Verhalten muss der Compiler etwas gemäß dem Standard tun, aber genau welche Auswahlmöglichkeiten der Standard gibt, hängt vom Compiler ab und muss nicht definiert (oder sogar konsistent) sein. Dinge wie Reihenfolge der Auswertung von Unterausdrücken fallen in diese Kategorie. Der Compiler kann diese in beliebiger Reihenfolge ausführen und dies in verschiedenen Builds oder sogar in verschiedenen Runs desselben Builds (unwahrscheinlich, aber erlaubt) anders machen.

14

Implementierung definiert Verhalten und undefiniertes Verhalten

Die Standard-C++ ist sehr spezifisch über die Auswirkungen der verschiedenen Konstrukte, insbesondere sollten Sie immer bewusst sein, diese Kategorien von Mühe:

  • Undefiniertes Verhalten bedeutet, dass keinerlei Garantien gegeben werden. Der Code könnte funktionieren, oder er könnte Ihre Festplatte oder make demons fly out your nose in Brand setzen. Was die C++ - Sprache betrifft, könnte absolut alles passieren. In der Praxis bedeutet dies, dass Sie einen nicht behebbaren Fehler haben. Wenn das passiert, können Sie nicht wirklich irgendetwas über Ihre Anwendung vertrauen (weil eine der Auswirkungen dieses undefinierten Verhaltens gerade gewesen sein könnte, den Speicher zu verschwenden, der vom Rest Ihrer Anwendung benutzt wird).Es ist nicht erforderlich, dass es konsistent ist. Wenn Sie also das Programm zweimal ausführen, erhalten Sie möglicherweise andere Ergebnisse. Es kann von den Mondphasen abhängen, von der Farbe des Hemdes, das du trägst, oder von absolut allem anderen.

  • Nicht spezifiziertes Verhalten bedeutet, dass das Programm muss etwas vernünftig und konsistent, aber es ist nicht erforderlich, Dokument dies.

  • Implementationsdefiniertes Verhalten ist ähnlich wie unspezifiziert, muss aber auch von den Compiler-Schreibern dokumentiert werden. Ein Beispiel dafür ist das Ergebnis einer reinterpret_cast. in der Regel, ändert es einfach den Typ eines Zeigers, ohne die Adresse zu ändern, aber das Mapping ist tatsächlich implementation-defined, so könnte ein Compiler Karte auf eine völlig andere Adresse, solange es diese Wahl dokumentiert. Ein anderes Beispiel ist die Größe eines int. Die C++ Standard es egal, ob es 2, 4 oder 8 Bytes, aber es muss die für alle diese

jedoch gemeinsam

Compiler dokumentiert ist, dass sie am besten vermieden sind. Wenn möglich, bleiben Sie bei einem Verhalten, das zu 100% vom C++ - Standard selbst angegeben wird. Auf diese Weise ist die Portabilität garantiert.

Sie müssen sich oft auch auf einige implementierungsdefinierte Verhaltensweisen verlassen. Es kann unvermeidlich sein, aber Sie sollten immer noch darauf achten und sich bewusst sein, dass Sie sich auf etwas verlassen, das sich zwischen verschiedenen Compilern ändern kann.

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

+1

UB sollte vermieden werden * wenn Sie sich um Portabilität * kümmern. Eine bestimmte Implementierung kann definieren, was für ein bestimmtes nicht definiertes Verhalten passiert, und in einigen Fällen (insbesondere Gerätetreiber und kleinere eingebettete Systeme) müssen Sie diese Dinge verwenden. –

+3

@Jerry: Nein, UB sollte vermieden werden * wenn es völlig undefiniert ist *. Wenn die Plattform/Implementierung/Runtime/Compiler weitere Garantien gibt, dann 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 keine solchen Garantien, undefiniert ist nur undefiniert und sollte um jeden Preis vermieden werden. – jalf

+0

"konsistent" könnte eine irreführende Beschreibung nicht spezifizierten Verhaltens sein. Es muss mit dem allgemeinen Kontext der Operation konsistent sein, zum Beispiel wenn ein Ausdruck einen "unspezifizierten Wert" hat, dann muss das Ergebnis * ein Wert sein, wenn Sie ihn speichern, muss der gespeicherte Wert danach mit sich selbst vergleichen, und so auf. Aber nicht spezifizierte Ergebnisse müssen im Laufe der Zeit nicht konsistent sein (gleiche Ausgabe für dieselbe Eingabe, wenn Sie sie erneut ausführen) oder sogar deterministisch. –

4

Die kurze Version:

Implementierung definiert Verhalten (IB): korrekt programmiert, aber unbestimmt *

undefinierte Verhalten (UB): falsch programmiert (! Dh ein Fehler)

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

+0

Wenn der Standard angibt, dass eine Aktion das implementierungsdefinierte Verhalten aufruft, müssen Implementierungen ein * konsistentes * Verhalten angeben, das aus dieser Aktion resultiert. Leider gibt es keine Verhaltenskategorie, für die eine Implementierung erforderlich wäre, um mögliche Konsequenzen zu spezifizieren, aber es wäre nicht erforderlich, dass bestimmte Konsequenzen konsequent auftreten. – supercat