Der vorzeichenlose Ganzzahlüberlauf ist sowohl im C- als auch im C ++ - Standard gut definiert. Zum Beispiel heißt es im C99-Standard ( §6.2.5/9
)
Eine Berechnung mit vorzeichenlosen Operanden kann niemals überlaufen, da ein Ergebnis, das nicht durch den resultierenden vorzeichenlosen Ganzzahltyp dargestellt werden kann, modulo um die Zahl reduziert wird, die eins größer ist als der größte Wert, der durch den resultierenden Typ dargestellt werden kann.
Beide Standards geben jedoch an, dass ein vorzeichenbehafteter Ganzzahlüberlauf ein undefiniertes Verhalten ist. Wieder aus dem C99-Standard ( §3.4.3/1
)
Ein Beispiel für ein nicht definiertes Verhalten ist das Verhalten beim Ganzzahlüberlauf
Gibt es einen historischen oder (noch besser!) Technischen Grund für diese Diskrepanz?
quelle
if (a + b < a)
). Der Überlauf bei der Multiplikation ist sowohl für vorzeichenbehaftete als auch für vorzeichenlose Typen schwierig.MAX_INT+1 == -0
während es sich um ein Zweierkomplement handelt, wäre esINT_MIN
Antworten:
Der historische Grund ist, dass die meisten C-Implementierungen (Compiler) nur das Überlaufverhalten verwendeten, das mit der verwendeten Ganzzahldarstellung am einfachsten zu implementieren war. C-Implementierungen verwendeten normalerweise dieselbe Darstellung, die von der CPU verwendet wurde - daher folgte das Überlaufverhalten der von der CPU verwendeten Ganzzahldarstellung.
In der Praxis können sich nur die Darstellungen für vorzeichenbehaftete Werte je nach Implementierung unterscheiden: das eigene Komplement, das Zweierkomplement, die Vorzeichengröße. Für einen Typ ohne Vorzeichen gibt es keinen Grund für den Standard, Variationen zuzulassen, da es nur eine offensichtliche binäre Darstellung gibt (der Standard erlaubt nur binäre Darstellung).
Relevante Zitate:
C99 6.2.6.1:3 :
C99 6.2.6.2:2 :
Heutzutage verwenden alle Prozessoren die Zweierkomplementdarstellung, aber der signierte arithmetische Überlauf bleibt undefiniert, und Compilerhersteller möchten, dass er undefiniert bleibt, da sie diese Undefiniertheit verwenden, um bei der Optimierung zu helfen. Siehe zum Beispiel diesen Blog-Beitrag von Ian Lance Taylor oder diese Beschwerde von Agner Fog und die Antworten auf seinen Fehlerbericht.
quelle
Abgesehen von Pascals guter Antwort (die sicher die Hauptmotivation ist) ist es auch möglich, dass einige Prozessoren eine Ausnahme beim Überlauf von vorzeichenbehafteten Ganzzahlen verursachen, was natürlich zu Problemen führen würde, wenn der Compiler "ein anderes Verhalten veranlassen" müsste ( Verwenden Sie z. B. zusätzliche Anweisungen, um einen möglichen Überlauf zu überprüfen und in diesem Fall anders zu berechnen.
Es ist auch erwähnenswert, dass "undefiniertes Verhalten" nicht "nicht funktioniert" bedeutet. Dies bedeutet, dass die Implementierung in dieser Situation tun kann, was sie will. Dies beinhaltet "das Richtige tun" sowie "die Polizei rufen" oder "abstürzen". Die meisten Compiler wählen, wenn möglich, "das Richtige tun", vorausgesetzt, dies ist relativ einfach zu definieren (in diesem Fall). Wenn Sie jedoch Überläufe in den Berechnungen haben, ist es wichtig zu verstehen, was dies tatsächlich zur Folge hat und dass der Compiler möglicherweise etwas anderes als das tut, was Sie erwarten (und dass dies sehr stark von der Compilerversion, den Optimierungseinstellungen usw. abhängen kann). .
quelle
int f(int x) { return x+1>x; }
mit der Optimierung kompilieren . GCC und ICC optimieren mit Standardoptionen die oben genannten Optionen aufreturn 1;
.int
je nach Optimierungsstufe unterschiedliche Ergebnisse bei Überlauf liefert , finden Sie unter ideone.com/cki8nM. Ich denke, dies zeigt, dass Ihre Antwort schlechte Ratschläge gibt.Bitte beachten Sie zunächst, dass C11 3.4.3 wie alle Beispiele und Fußnoten kein normativer Text ist und daher nicht für das Zitieren relevant ist!
Der relevante Text, der besagt, dass der Überlauf von Ganzzahlen und Gleitkommazahlen ein undefiniertes Verhalten ist, lautet wie folgt:
C11 6.5 / 5
Eine Erläuterung zum Verhalten vorzeichenloser Ganzzahltypen finden Sie hier:
C11 6.2.5 / 9
Dies macht vorzeichenlose Ganzzahltypen zu einem Sonderfall.
Beachten Sie auch, dass es eine Ausnahme gibt, wenn ein Typ in einen signierten Typ konvertiert wird und der alte Wert nicht mehr dargestellt werden kann. Das Verhalten ist dann lediglich implementierungsdefiniert, obwohl ein Signal ausgelöst werden kann.
C11 6.3.1.3
quelle
Zusätzlich zu den anderen Themen erwähnt, ohne Vorzeichen Mathe Windung, die macht die unsigned Integer - Typen verhalten sich als abstrakte algebraischen Gruppen (das bedeutet unter anderem, für jedes Paar von Werten
X
undY
wird es einen anderen Wert existieren ,Z
so dassX+Z
Wille, wenn sie richtig gegossen gleich ). Wenn vorzeichenlose Werte lediglich Speicherorttypen und keine Zwischenausdruckstypen waren (z. B. wenn es kein vorzeichenloses Äquivalent des größten Ganzzahltyps gab und arithmetische Operationen für vorzeichenlose Typen sich so verhielten, als würden sie zuerst in größere vorzeichenbehaftete Typen konvertiert, dann dort Ein definiertes Umhüllungsverhalten wäre nicht so wichtig, aber es ist schwierig, Berechnungen in einem Typ durchzuführen, der beispielsweise keine additive Inverse aufweist.Y
undY-Z
wird, wenn richtig besetzt, gleichX
Dies hilft in Situationen, in denen das Umlaufverhalten tatsächlich nützlich ist - beispielsweise bei TCP-Sequenznummern oder bestimmten Algorithmen wie der Hash-Berechnung. Dies kann auch in Situationen hilfreich sein, in denen ein Überlauf erkannt werden muss, da das Durchführen von Berechnungen und das Überprüfen, ob sie übergelaufen sind, häufig einfacher ist als das vorherige Überprüfen, ob sie überlaufen würden, insbesondere wenn die Berechnungen den größten verfügbaren Ganzzahltyp beinhalten.
quelle
a+b-c
in einer Schleife berechnet wird, sondernb
undc
konstant sind innerhalb dieser Schleife, kann es hilfreich seine Berechnung zu bewegen(b-c)
außerhalb der Schleife, aber das tut unter anderem erfordern würde , die(b-c)
einen Wert , der, wenn hinzugefügta
, ergibta+b-c
, was wiederum erfordert,c
dass ein Additiv invers ist.(a+b)-c
equalsa+(b-c)
ob der arithmetischen Wertb-c
innerhalb des Typs darstellbarer ist, wird die Substitution unabhängig von dem möglichen Wertebereich gültig sein(b-c)
.Vielleicht liegt ein weiterer Grund dafür, warum vorzeichenlose Arithmetik definiert wird, darin, dass vorzeichenlose Zahlen Ganzzahlen modulo 2 ^ n bilden, wobei n die Breite der vorzeichenlosen Zahl ist. Vorzeichenlose Zahlen sind einfach Ganzzahlen, die durch Binärziffern anstelle von Dezimalstellen dargestellt werden. Das Ausführen der Standardoperationen in einem Modulsystem ist gut verstanden.
Das Zitat des OP bezieht sich auf diese Tatsache, hebt aber auch die Tatsache hervor, dass es nur eine eindeutige, logische Möglichkeit gibt, vorzeichenlose Ganzzahlen binär darzustellen. Im Gegensatz dazu werden vorzeichenbehaftete Zahlen am häufigsten mit dem Zweierkomplement dargestellt, es sind jedoch auch andere Auswahlmöglichkeiten möglich, wie im Standard (Abschnitt 6.2.6.2) beschrieben.
Durch die Zweierkomplementdarstellung können bestimmte Operationen im Binärformat sinnvoller sein. Das Inkrementieren negativer Zahlen ist beispielsweise dasselbe wie bei positiven Zahlen (unter Überlaufbedingungen zu erwarten). Einige Vorgänge auf Maschinenebene können für vorzeichenbehaftete und vorzeichenlose Nummern identisch sein. Bei der Interpretation des Ergebnisses dieser Operationen sind einige Fälle jedoch nicht sinnvoll - positiver und negativer Überlauf. Darüber hinaus unterscheiden sich die Überlaufergebnisse in Abhängigkeit von der zugrunde liegenden vorzeichenbehafteten Darstellung.
quelle