Ist der Überlauf von vorzeichenbehafteten Ganzzahlen in C++ immer noch undefiniert?

Lesezeit: 7 Minuten

Ist der Uberlauf von vorzeichenbehafteten Ganzzahlen in C immer noch
Archie

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.

  • 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

Ist der Uberlauf von vorzeichenbehafteten Ganzzahlen in C immer noch
Andy Prowl

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.

  • Dieser Absatz würde auch implizieren, dass unsigned overflow undefiniert ist, was nicht der Fall ist.

    – Archie

    24. April 2013 um 9:54 Uhr

  • @Archie: Nicht wirklich, da vorzeichenlose Werte definiert sind modulo den vorzeichenlosen Bereich.

    – Leichtigkeitsrennen im Orbit

    24. April 2013 um 9:56 Uhr

  • @Archie: Ich habe versucht zu klären, aber im Grunde hast du die Antwort von LightnessRacesinOrbit bekommen

    – Andy Prowl

    24. April 2013 um 9:59 Uhr

  • Es spielt eigentlich keine Rolle, ob vorzeichenloser Überlauf definiert ist oder nicht, wenn er aufgrund der Modulo-Berechnung nicht auftreten kann …

    – Aconcagua

    15. Dezember 2018 um 9:13 Uhr

  • Es gibt vorzeichenlose Operationen, deren Ergebnis nicht “mathematisch definiert” ist – insbesondere die Division durch Null -, also ist Ihre Formulierung vielleicht nicht ganz so, wie Sie sie in diesem Satz gemeint haben. ITYM das wenn das Ergebnis mathematisch definiert istdann ist es auch in C++ definiert.

    – Toby Speight

    4. März 2019 um 19:18 Uhr


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.

  • Es mag erwähnenswert sein, dass sich viele Leute mehr Sorgen um die Möglichkeiten von Traps machen, aber Compiler-Annahmen sind tatsächlich heimtückischer (einer der Gründe, warum ich mir wünschte, es gäbe eine Kategorie zwischen implementierungsdefiniertem und undefiniertem Verhalten – im Gegensatz zu implementierungsdefiniertem Verhalten was bestimmte Implementierungen erfordert, um etwas in konsistent dokumentierter Weise zu tun, möchte ich ein “implementierungsbeschränktes” Verhalten, das Implementierungen erfordern würde, um alles anzugeben, was als Folge von etwas passieren könnte (die Spezifikationen könnten explizit undefiniertes Verhalten enthalten, aber .. .

    – Superkatze

    23. Februar 2015 um 18:35 Uhr


  • … Implementierungen würden ermutigt, spezifischer zu sein, wenn dies praktikabel ist). Auf einer Hardware, bei der Zweierkomplementzahlen natürlich “umbrechen” würden, gibt es keinen vernünftigen Grund für Code, der möchte, dass ein umschlossenes ganzzahliges Ergebnis viele Anweisungen ausführt, die versuchen, eine Berechnung ohne Ganzzahlüberlauf durchzuführen, die die Hardware in nur ein oder zwei Anweisungen ausführen könnte .

    – Superkatze

    23. Februar 2015 um 18:52 Uhr

  • @supercat Tatsächlich kann der Code, der ein umschlossenes Ergebnis haben möchte (auf 2er-Komplement-CPUs) einfach Operanden in entsprechende vorzeichenlose Typen umwandeln und die Operation ausführen (und dann zurückwerfen, um einen implementierungsdefinierten Wert zu erhalten): Dies funktioniert für Addition, Subtraktion und Multiplikation . Das einzige Problem ist mit Division, Modulo und solchen Funktionen wie abs. Für diese Operationen, wenn es funktioniert, sind nicht mehr Anweisungen erforderlich als mit signierter Arthmetik.

    – Ruslan

    9. Oktober 2016 um 14:29 Uhr


  • @Ruslan: In Fällen, in denen Code ein präzise verpacktes Ergebnis benötigt, wäre eine Umwandlung in unsigned hässlich, generiert aber nicht unbedingt zusätzlichen Code. Ein größeres Problem wäre Code, der „potenziell interessante“ Kandidaten schnell identifizieren muss, der die meiste Zeit damit verbringen wird, uninteressante Kandidaten abzulehnen. Wenn man einem Compiler die Freiheit gibt, zusätzliche Genauigkeit mit vorzeichenbehafteten Integer-Werten willkürlich beizubehalten oder zu verwerfen, aber erfordert, dass eine Umwandlung in einen Integer-Typ jede solche Genauigkeit abschneidet, ermöglicht dies die meisten nützlichen Optimierungen, die durch Überlauf von UB erreicht würden , …

    – Superkatze

    9. Oktober 2016 um 17:57 Uhr

  • …aber würde Code erlauben, der eine präzise Umhüllung benötigt, um eine statt zwei Umwandlungen zu verwenden (z (int)(x+y)>z würde ein verpacktes Ergebnis vergleichen) und würde auch Programmierern das Schreiben ermöglichen x+y>z in Fällen, in denen es akzeptabel wäre, dass der Code im Falle eines Überlaufs 0 oder 1 zurückgibt Vorausgesetzt, es hat keine anderen Nebenwirkungen. Wenn entweder 0 oder 1 ein gleichermaßen akzeptables Ergebnis wäre, lassen Sie den Programmierer das schreiben und nicht eines von beiden (long)x+y>z oder (int)((unsigned)x+y)>z würde es Compilern ermöglichen, auszuwählen, welche der letzteren Funktionen in einem bestimmten Kontext billiger ist [each would be cheaper in some cases].

    – Superkatze

    9. Oktober 2016 um 18:02 Uhr

Ist der Uberlauf von vorzeichenbehafteten Ganzzahlen in C immer noch
EnzoR

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]

993570cookie-checkIst der Überlauf von vorzeichenbehafteten Ganzzahlen in C++ immer noch undefiniert?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy