Wie wir wissen, ist ein vorzeichenbehafteter Ganzzahlüberlauf ein undefiniertes Verhalten . In der C ++ 11- cstdint
Dokumentation gibt es jedoch etwas Interessantes :
Ganzzahliger Typ mit Vorzeichen mit einer Breite von genau 8, 16, 32 bzw. 64 Bit ohne Auffüllbits und Verwendung des Zweierkomplements für negative Werte (nur bereitgestellt, wenn die Implementierung den Typ direkt unterstützt)
Und hier ist meine Frage: Da die Norm ausdrücklich sagt , dass für int8_t
, int16_t
, int32_t
und int64_t
negative Zahlen sind 2-Komplement, ist immer noch Überlauf dieser Art ein nicht definiertes Verhalten?
Bearbeiten Ich habe die C ++ 11- und C11-Standards überprüft und Folgendes gefunden:
C ++ 11, §18.4.1:
Der Header definiert alle Funktionen, Typen und Makros wie 7.20 im C-Standard.
C11, §7.20.1.1:
Der Typedef-Name
intN_t
bezeichnet einen vorzeichenbehafteten Integer-Typ mit der Breite N, keinen Füllbits und einer Zweierkomplementdarstellung. Somitint8_t
bezeichnet ein solcher vorzeichenbehaftete Ganzzahl - Typ mit einer Breite von genau 8 Bits.
Antworten:
Ja. Gemäß Absatz 5/4 des C ++ 11-Standards (in Bezug auf alle Ausdrücke im Allgemeinen):
Die Tatsache, dass für diese vorzeichenbehafteten Typen eine Zweierkomplementdarstellung verwendet wird, bedeutet nicht, dass bei der Bewertung von Ausdrücken dieser Typen das arithmetische Modulo 2 ^ n verwendet wird.
In Bezug auf vorzeichenlose Arithmetik legt der Standard andererseits ausdrücklich fest, dass (Ziffer 3.9.1 / 4):
Dies bedeutet, dass das Ergebnis einer vorzeichenlosen arithmetischen Operation immer " mathematisch definiert " ist und das Ergebnis immer innerhalb des darstellbaren Bereichs liegt; daher gilt 5/4 nicht. Fußnote 46 erklärt dies:
quelle
Nur weil ein Typ für die Verwendung der 2s-Komplementdarstellung definiert ist, folgt daraus nicht, dass der arithmetische Überlauf in diesem Typ definiert wird.
Das undefinierte Verhalten des vorzeichenbehafteten arithmetischen Überlaufs wird verwendet, um Optimierungen zu ermöglichen. Zum Beispiel kann der Compiler annehmen, dass wenn
a > b
danna + 1 > b
auch; Dies gilt nicht für vorzeichenlose Arithmetik, bei der die zweite Prüfung durchgeführt werden müsste, da die Möglichkeit besteht, dassa + 1
sich dies ändert0
. Einige Plattformen können auch ein Trap-Signal bei arithmetischem Überlauf erzeugen (siehe z. B. http://www.gnu.org/software/libc/manual/html_node/Program-Error-Signals.html ). Der Standard lässt dies weiterhin zu.quelle
abs
. Für diese Operationen, wenn es funktioniert, sind nicht mehr Anweisungen erforderlich als mit signierter Arthmetik.(int)(x+y)>z
umbrochen werden muss, eine Umwandlung anstelle von zwei verwendet (z. B. würde ein umbrochenes Ergebnis verglichen), und würde es Programmierern auch ermöglichen,x+y>z
in Fällen zu schreiben, in denen es akzeptabel wäre, wenn Code für den Fall 0 oder 1 ergibt Überlauf vorausgesetzt, es hat keine andere Nebenwirkung . Wenn entweder 0 oder 1 ein ebenso akzeptables Ergebnis wäre, würde der Programmierer dies schreiben lassen(long)x+y>z
oder(int)((unsigned)x+y)>z
es den Compilern ermöglichen, auszuwählen, welche der letzteren Funktionen in einem bestimmten Kontext billiger war [jede wäre in einigen Fällen billiger].Ich würde es wetten.
Aus der Standarddokumentation (S. 4 und 5):
quelle