Frage

Ich habe ein bisschen in der C -Spezifikation gelesen, dass nicht signierte Variablen (insbesondere nicht signiert int) Führen Sie einige sogenannte durch Wickeln Sie herum auf Ganzzahlüberlauf, obwohl ich nichts in signierten Variablen finden konnte, außer dass ich mitgegangen bin undefiniertes Verhalten.

Mein Professor sagte mir, dass ihre Werte auch umwickelt werden (vielleicht meinte er nur GCC). Ich dachte, die Teile werden gerade abgeschnitten und die Teile, mit denen ich gelassen habe, geben mir einen seltsamen Wert!

Was Wickel herum ist und wie unterscheidet es sich nur von nur abgeschnittenen Bits.

War es hilfreich?

Lösung

Signierte ganzzahlige Variablen haben kein Wrack-Verhalten in der C-Sprache. Der signierte Ganzzahlüberlauf während arithmetischer Berechnungen erzeugt undefiniertes Verhalten. Beachten Sie übrigens, dass der von Ihnen erwähnte GCC -Compiler für die Implementierung bekannt ist Strenge Überlaufsemantik In Optimierungen nutzt es die Freiheit, die solche undefinierten Verhaltenssituationen bereitzustellen: GCC -Compiler geht davon aus, dass signierte ganzzahlige Werte nie umwickeln. Das bedeutet, dass GCC tatsächlich einer der Compiler ist, in denen Sie kann nicht Verlassen Sie sich auf ein Wrack-Verhalten von signierten Ganzzahltypen.

Zum Beispiel kann der GCC -Compiler dies für eine Variable annehmen int i die folgende Bedingung

if (i > 0 && i + 1 > 0)

entspricht nur einem bloßen

if (i > 0)

Genau das ist was Strenge Überlaufsemantik meint.

Unsignierte ganzzahlige Typen implementieren Modulo -Arithmetik. Das Modulo ist gleich 2^N wo N ist die Anzahl der Bits in der Wertdarstellung des Typs. Aus diesem Grund scheinen unsignierte ganzzahlige Typen tatsächlich mit dem Überlauf umzugehen.

Die C -Sprache führt jedoch niemals arithmetische Berechnungen in Domänen durch, die kleiner sind als die von int/unsigned int. Typ unsigned short int Das Sie in Ihrer Frage erwähnen, wird normalerweise zum Typ -Typ befördert int in Ausdrücken vor Beginn aller Berechnungen (vorausgesetzt, der Bereich von unsigned short passt in den Bereich von int). Was bedeutet, dass 1) die Berechnungen mit unsigned short int wird in der Domäne von vorgeformt int, mit Überlauf, wenn int Überläufe, 2) Überlauf während solcher Berechnungen führt zu undefiniertem Verhalten, nicht zu einem Verhalten von Wickeln.

Zum Beispiel erzeugt dieser Code eine Umwicklung

unsigned i = USHRT_MAX;
i *= INT_MAX; /* <- unsigned arithmetic, overflows, wraps around */

während dieser Code

unsigned short i = USHRT_MAX;
i *= INT_MAX; /* <- signed arithmetic, overflows, produces undefined behavior */

führt zu undefiniertem Verhalten.

Wenn nein int Überlauf tritt auf und das Ergebnis wird wieder auf eine konvertiert unsigned short int Typ, es wird erneut durch Modulo reduziert 2^N, was so aussieht, als ob sich der Wert umwickelt hat.

Andere Tipps

Stellen Sie sich vor, Sie haben einen Datentyp, der nur 3 Bit breit ist. Auf diese Weise können Sie 8 unterschiedliche Werte von 0 bis 7 darstellen. Wenn Sie 1 zu 7 hinzufügen, werden Sie "um 0 bis 0 umwickeln", da Sie nicht genügend Bits haben, um den Wert 8 (1000) darzustellen.

Dieses Verhalten ist für nicht signierte Typen gut definiert. es ist nicht Für signierte Typen gut definiert, da es mehrere Methoden zur Darstellung signierter Werte gibt und das Ergebnis eines Überlaufs basierend auf dieser Methode unterschiedlich interpretiert wird.

Sign-Magnitude: Das oberste Bit repräsentiert das Zeichen; 0 für positiv, 1 für negativ. Wenn mein Typ wieder drei Bits breit ist, kann ich signierte Werte wie folgt darstellen:

000  =  0
001  =  1
010  =  2
011  =  3
100  = -0
101  = -1
110  = -2
111  = -3

Da ein Bit für das Zeichen aufgenommen wird, habe ich nur zwei Bits, um einen Wert von 0 bis 3 zu codieren. Wenn ich 1 bis 3 hinzufüge, überlaufe ich mit -0 als Ergebnis. Ja, es gibt zwei Darstellungen für 0, einen positiv und einen negativ. Sie werden nicht all das oft auf die Darstellung der Vorstellung von Vorstellungen stoßen.

Einerkomplement: Der negative Wert ist die bitgewiäre Interesse des positiven Werts. Auch hier verwenden Sie den Drei-Bit-Typ:

000  =  0
001  =  1
010  =  2
011  =  3
100  = -3
101  = -2
110  = -1 
111  = -0

Ich habe drei Bits, um meine Werte zu codieren, aber der Bereich beträgt [-3, 3]. Wenn ich 1 bis 3 hinzufüge, überlaufe ich mit -3 als Ergebnis. Dies unterscheidet sich von dem obigen Sign-Magnitude-Ergebnis. Auch hier gibt es zwei Codierungen für 0 mit dieser Methode.

Zwei-Komplement: Der negative Wert ist die bitweise Umkehrung des positiven Werts plus 1. im Drei-Bit-System:

000  =  0
001  =  1
010  =  2
011  =  3
100  = -4
101  = -3
110  = -2
111  = -1

Wenn ich 1 bis 3 hinzufüge, überlaufe ich als Ergebnis mit -4, was sich von den beiden vorherigen Methoden unterscheidet. Beachten Sie, dass wir einen etwas größeren Wertebereich [-4, 3] und nur eine Darstellung für 0 haben.

Das Komplement von Two ist wahrscheinlich die häufigste Methode, um signierte Werte darzustellen, aber es ist nicht die einzige, daher kann der C -Standard keine Garantien dafür geben, was passieren wird, wenn Sie einen signierten Ganzzahltyp überfüllen. So lässt es das Verhalten nicht definiert Der Compiler muss sich also nicht mit der Interpretation mehrerer Darstellungen befassen.

Das undefiniertes Verhalten stammt aus frühen Tragbarkeitsproblemen, wenn signierte Ganzzahltypen entweder als Zeichen und Größe, das oder zwei Komplements für zwei Komplemente dargestellt werden können.

Heutzutage repräsentieren alle Architekturen Ganzzahlen als Ergänzung von Two, die sich umwickeln. Seien Sie jedoch vorsichtig: Da Ihr Compiler zu Recht davon ausgeht, dass Sie nicht und definiertes Verhalten ausführen, können Sie bei der Optimierung auf seltsame Fehler stoßen.

In einer signierten 8-Bit-Ganzzahl könnte die intuitive Definition von Wrap umblicken, wie von +127 bis -128-in zweier Komplement binär: 0111111 (127) und 1000000 (-128). Wie Sie sehen können, ist dies der natürliche Fortschritt bei der Inkrementierung der Binärdaten-ohne sie als eine Ganzzahl darzustellen, signiert oder nicht signiert. Gegen intuitiv findet der tatsächliche Überlauf statt, wenn sich der Wickelgefühl der unsignierten Ganzzahl von -1 (11111111) auf 0 (00000000) bewegen.

Dies beantwortet die tiefere Frage nicht, was das richtige Verhalten ist, wenn eine signierte Ganzzahl überläuft, da es kein "korrektes" Verhalten gemäß dem Standard gibt.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top