Wie beurteilt man einen Überlauf beim Hinzufügen von Vorzeichen zu unsigned?

8

Ich versuche, den Überlauf zu erkennen, wenn ich einen vorzeichenbehafteten Offset zu einer Position ohne Vorzeichen hinzufüge

%Vor%

Wie kann ich überprüfen, ob das Ergebnis über- oder unterläuft?

Ich habe an einen hässlichen Weg gedacht, bin mir aber seiner Richtigkeit nicht sicher.

  • Unterlauf: offset < 0 && position + offset >= position
  • Überlauf: offset > 0 && position + offset <= position

Und ich frage mich auch, ob es einen eleganteren Weg dafür gibt.

Aktualisierung:

Was ist die beste Lösung, wenn der Offset groß ist?

%Vor%     
rogerz 03.11.2011, 09:18
quelle

3 Antworten

1

Ihre Prüfung (en) ist (sind) korrekt. Ich sehe jetzt keinen eleganteren Weg, vielleicht auch nicht.

Warum die Bedingungen stimmen: Arithmetik am uint32_t ist arithmetisch modulo 2 ^ 32. Die Umwandlung von int32_t nach uint32_t ist normalerweise die Neuinterpretation des Bitmusters (jedenfalls, wie @caf darauf hingewiesen hat, ist es hier eine Reduktion modulo 2 ^ 32, also funktioniert es definitiv). Betrachte position und offset als beliebige Ganzzahlen. Überlauf passiert genau dann, wenn
position + offset >= 2^32 . Aber offset < 2^31 , also position + offset < position + 2^31 , was kleiner ist als position + 2^32 , der nächste Wert, der auf position modulo 2 ^ 32 reduziert wird, also als uint32_t , dann position + offset < position . Auf der anderen Seite, wenn offset > 0 und position + offset < position , ist offenbar ein Überlauf aufgetreten. Unterlauf passiert genau dann, wenn position + offset < 0 als mathematische Ganzzahlen verwendet wird. Seit offset >= -2^31 zeigt eine ähnliche Argumentation, dass Unterlauf genau dann aufgetreten ist, wenn offset < 0 && position + offset > position .

    
Daniel Fischer 03.11.2011, 09:28
quelle
1

Die folgende Funktion prüft auf Überlauf / Unterlauf, wenn ein int32_t zu einem uint32_t hinzugefügt wird. Es enthält auch einige Testfälle als Beweis für die Richtigkeit.

%Vor%     
Ambroz Bizjak 03.11.2011 11:00
quelle
0

So können Sie es tun:

%Vor%

Das Suffix u soll sicherstellen, dass die 0xFFFFFFFF-Konstante vom Typ unsigned ist (Hexadezimalkonstanten ohne Suffixe können abhängig vom Wert und wie Ihr Compiler int, long und long long definiert) und daher der Ausdruck nach links sein von & lt; ist nicht signiert. Es ist vielleicht nicht notwendig, aber ich bin ein bisschen müde, um herauszufinden, ob es nicht ist. Es wird nicht weh tun.

Die (uint32) Umwandlungen sollen den Compiler zum Schweigen bringen, der denkt, dass wir etwas Dummes tun (Vergleichen mit Vorzeichen).

UPDATE : Wenn int32 eine Zweierkomplementdarstellung und offset = -0x80000000 hat, darf der Ausdruck -offset ein implementationsdefiniertes Signal auslösen oder möglicherweise sogar undefiniertes Verhalten nach C-Standard verursachen ( siehe Abschnitte 6.3.1.3 Signed and unsigned integers und 7.20.6.1 The abs, labs and llabs functions von C99), aber praktisch tritt dies nie auf, weil auf den meisten Plattformen die Negation als eine einfache Anweisung (oder einige) implementiert wird, die keine Ausnahme / Interrupt / Trap / Ereignis in der CPU auslöst und es gibt wenig Wert beim Erzeugen von Extra-Code, um nach diesem Kantenfall zu suchen, insbesondere, da ganze Zahlen im 2er-Komplement-Code dargestellt sind und der absolute Wert von -0x80000000 sowieso 0x80000000 ist, was nützlich sein kann (zB für Absolutwertberechnungen). Die CPU interessiert sich nicht besonders für vorzeichenbehaftete Ganzzahlen und verwendet sogar die gleichen Additions- und Subtraktionsbefehle für beide (dies ist der Vorteil des Zweierkomplements), und sie kümmert sich selten um Integer-Überläufe, weil sie routinemäßig in Software vorkommen und eine Möglichkeit darstellen Leben. Seien Sie sich dessen bewusst, aber schwitzen Sie es nicht.

Bitte lesen Sie, wie diese im SafeInt von C ++ ( Code , Intro , Auf MSDN , Video ) und IntSafe für C ( Intro + Code , Auf MSDN ).

    
Alexey Frunze 03.11.2011 11:03
quelle