Wie wir wissen, ist der Überlauf von vorzeichenbehafteten Ganzzahlen ein undefiniertes Verhalten. Aber es gibt etwas Interessantes in C++11 cstdint
Dokumentation:
vorzeichenbehafteter Integer-Typ mit einer Breite von genau 8, 16, 32 bzw. 64 Bit ohne Füllbits und Verwenden des Zweierkomplements für negative Werte (nur bereitgestellt, wenn die Implementierung den Typ direkt unterstützt)
Siehe Verlinkung
Und hier meine Frage: da sagt die Norm explizit das für int8_t
, int16_t
, int32_t
und int64_t
Negative Zahlen sind 2er-Komplemente, ist der Überlauf dieser Typen immer noch ein undefiniertes 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 genauso 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, ohne Füllbits und als Zweierkomplement-Darstellung. Daher, int8_t
bezeichnet einen solchen vorzeichenbehafteten Integer-Typ mit einer Breite von genau 8 Bit.
Ist der Überlauf dieser Typen immer noch ein undefiniertes Verhalten?
Jawohl. Gemäß Paragraph 5/4 des C++11-Standards (in Bezug auf jeden Ausdruck im Allgemeinen):
Wenn bei der Auswertung eines Ausdrucks das Ergebnis mathematisch nicht definiert ist oder nicht im Bereich darstellbarer Werte für seinen Typ liegt, Das Verhalten ist undefiniert. […]
Die Tatsache, dass für diese vorzeichenbehafteten Typen eine Zweierkomplementdarstellung verwendet wird, bedeutet nicht, dass bei der Auswertung von Ausdrücken dieser Typen Arithmetik Modulo 2^n verwendet wird.
Über ohne Vorzeichen Arithmetik hingegen legt der Standard explizit fest (Paragraph 3.9.1/4):
Ganzzahlen ohne Vorzeichen, deklariert unsigned
, soll den Gesetzen der Arithmetik modulo 2^n gehorchen wobei n die Anzahl der Bits in der Wertdarstellung dieser bestimmten Ganzzahlgröße ist
Das bedeutet, dass das Ergebnis einer arithmetischen Operation ohne Vorzeichen immer “mathematisch definiert“, und das Ergebnis liegt immer im darstellbaren Bereich; daher gilt 5/4 nicht. Fußnote 46 erklärt dies:
46) Das impliziert das ohne Vorzeichen Die Arithmetik läuft nicht über, da ein Ergebnis, das nicht durch den resultierenden ganzzahligen Typ ohne Vorzeichen dargestellt werden kann, modulo um die Zahl reduziert wird, die um eins größer ist als der größte Wert, der durch den resultierenden ganzzahligen Typ ohne Vorzeichen dargestellt werden kann.
Nur weil ein Typ so definiert ist, dass er die Zweierkomplementdarstellung verwendet, folgt daraus nicht, dass ein arithmetischer Überlauf in diesem Typ definiert wird.
Das undefinierte Verhalten des vorzeichenbehafteten arithmetischen Überlaufs wird verwendet, um Optimierungen zu ermöglichen; Beispielsweise kann der Compiler davon ausgehen, dass if a > b
dann a + 1 > b
Auch; Dies gilt nicht für vorzeichenlose Arithmetik, bei der die zweite Überprüfung aufgrund der Möglichkeit durchgeführt werden müsste a + 1
könnte sich umwickeln 0
. Außerdem können einige Plattformen bei einem arithmetischen Überlauf ein Trap-Signal generieren (siehe z http://www.gnu.org/software/libc/manual/html_node/Program-Error-Signals.html); die Norm lässt dies weiterhin zu.
Darauf würde ich wetten.
Aus der Standarddokumentation (Seite 4 und 5):
1.3.24 undefiniertes Verhalten
Verhalten, für das diese Internationale Norm keine Anforderungen stellt
[ Note: Undefined behavior may be expected when this International
Standard omits any explicit definition of behavior or when a program
uses an erroneous construct or erroneous data. Permissible undefined
behavior ranges from ignoring the situation completely with
unpredictable results, to behaving during translation or program
execution in a documented manner characteristic of the environment
(with or without the issuance of a diagnostic message), to terminating
a translation or execution (with the issuance of a diagnostic
message). Many erroneous program constructs do not engender undefined
behavior; they are required to be diagnosed.– end note]
Vergiss nie, dass das einzige primär Dokumentation für C++ ist der Standard. Alles andere, sogar ein Wiki wie CppReference, ist eine sekundäre Quelle. Das bedeutet nicht, dass es falsch ist; nur nicht ganz zuverlässig.
– Nicol Bolas
24. April 2013 um 9:27 Uhr
Ich würde erwarten, dass es UB ist, es gibt keine Ausnahme für diese Typen in C, ich verstehe nicht, warum C++ eine hinzufügen würde.
– Daniel Fischer
24. April 2013 um 9:35 Uhr
mögliches Duplikat von Zeigen C99-Integertypen mit Vorzeichen, die in stdint.h definiert sind, ein wohldefiniertes Verhalten im Falle eines Überlaufs?
– ekatmur
24. April 2013 um 9:58 Uhr
Ich bin etwas verwirrt: Wo ist das Verb im Satz “Vorzeichenbehafteter Ganzzahltyp mit einer Breite von genau 8, 16, 32 bzw. 64 Bit ohne Füllbits und mit Zweierkomplement für negative Werte (nur bereitgestellt, wenn die Implementierung dies direkt unterstützt). der Typ)?” Fehlt ein bisschen? Was heißt das?
– JSC
21. Dezember 2015 um 8:41 Uhr
C++11 basiert auf C99, nicht auf C11. Aber das ist sowieso nicht wichtig
– LF
12. Juli 2019 um 5:39 Uhr