Überlauf macht Vorzeichenwechsel

Gast #1955155
Hallo,
ich hätte mal ein Problem beim C Programmieren:
1
unsigned long int a,b,c;
2

3
b = blablub 
4
c = blubbla
5

6
a = b + c; // Hier könnte ein Überlauf passieren
Ich addiere zwei signed long int. Wie kann ich verhindern, das bei 
Überlauf das Vorzeichen des Ergebnisses falsch ist?
Ich würde dann lieber das Ergebnis auf 0x7FFFFFFF bzw. 0x80000000 
begrenzt haben?
Moderator (Firma: Titel) Persönliche Seite
Bastelmaus schrieb:
> Wie kann ich verhindern, das bei Überlauf das Vorzeichen
> des Ergebnisses falsch ist?
Bei einem unsigned long kann niemals das Vorzeichen falsch sein. Es 
kann bestenfalls das Ergebniss an sich falsch sein...

> Ich würde dann lieber das Ergebnis auf 0x7FFFFFFF bzw. 0x80000000
> begrenzt haben?
Warum?

Oder willst du einfach nur erkennen, dass du einen Überlauf hattest?
Hier gibt es ein paar Ideen dazu:

http://bytes.com/topic/c/answers/523303-how-test-overflow

(erstes Suchergebnis bei Google nach "c overflow test")

Wirklich schade, daß C da nichts besseres bietet, denn viele CPUs haben 
intern ja ein Flag, daß anzeigt, ob die vorherige Rechnenoperation 
übergelaufen ist. Mir fällt da auf Anhieb der gute alte 6502 ein:

http://www.6502.org/tutorials/vflag.html
Persönliche Seite
Lothar Miller schrieb:
> Bastelmaus schrieb:
>> Wie kann ich verhindern, das bei Überlauf das Vorzeichen
>> des Ergebnisses falsch ist?
> Bei einem unsigned long kann niemals das Vorzeichen falsch sein. Es
> kann bestenfalls das Ergebniss an sich falsch sein...

Das Ergebnis ist immer richtig wenn man beruecksichtigt dass es sich 
hier um einen Restklassenring handelt.
Michael G. schrieb:
> Das Ergebnis ist immer richtig wenn man beruecksichtigt dass es sich
> hier um einen Restklassenring handelt.

Das mag meistens so sein, aber laut C Standard ist ein Integer Overflow 
nicht definiert und implementierungsabhängig. Ein mögliches Verhalten 
bei einem Integer Overflow wäre also auch, daß der Chip in Rauch aufgeht 
:-)
Gast
Bastelmaus schrieb:
> unsigned long int a,b,c;

oh Mist ich wollte natürlich schreiben :-(
1
signed long int a,b,c;
2

3
b = blablub 
4
c = blubbla
5

6
a = b + c; // Hier könnte ein Überlauf passieren
sorry tut mir ganz doll leid, ich war zu hastig.
Können wir nochmal ganz von vorne anfangen?
Moderator (Firma: Titel) Persönliche Seite
Bastelmaus schrieb:
> Können wir nochmal ganz von vorne anfangen?
Dann kannst du abfragen, ob sich bei der Addition ein unerwartetes 
Ergebnis ergibt und den Wert anschliessend begrenzen. Etwa so:
1
  signed long int a,b,c;
2

3
  b = blablub 
4
  c = blubbla
5

6
  a = b + c;
7
  if (a<0 && b>0 && c>0) a=0x7fffffff;
8
  if (a>0 && b<0 && c<0) a=0x80000000;
Du kannst auch einen Overflow detektieren, indem du vom maximal 
möglichen signed int Wert zuerst a abziehst. Dadurch erhältst du einen 
Wert, den b nicht überschreiten darf, weil es sonst zu einem Overflow 
kommt.

Hat ein bischen was von:
   Ich hab schon 80 Euro Schulden
   Wenn ich maximal in Summe 100 Euro Schulden machen darf,
   wieviele Schulden dürfen dann noch dazu kommen, damit mein
   100€ Budget nicht überschritten wird?
   Ich würde gerne noch 40€ Schulden machen, überlaufe ich damit
   meinen Rahmen oder nicht?

Wo das hinführt, wenn man Overflows erst im Nachhinein detektiert, sieht 
man ja aktuell ...
Gast
Lothar Miller schrieb:
1
> a = b + c;
2
> if (a<0 && b>0 && c>0) a=0x7fffffff;
3
> if (a>0 && b<0 && c<0) a=0x80000000;
Vielen Dank :-) ich hatte Tomaten auf den Augen und hab den Wald vor 
lauter Bäumen nicht gesehen.

Aber müsste man nicht auch berücksichtigen wenn a = 0 ist?
Gast
Nix Spezialität:

0x70000000 =  1879048192
0x90000000 = -1879048192

Alles angenommen 32 Bit signed. Oder einfacher ohne Berücksichtigung 
signed/unsigned (die reine Addition braucht im 2er-Komplement darauf 
keine Rücksicht nehmen) 0x70000000 + 0x90000000 = 0x100000000. In 32 Bit 
passt das nicht mehr, die 1 fällt links raus (bzw. ins Carry-Flag) und 
die restlichen Bits sind ja alle 0.
Moderator (Firma: Titel) Persönliche Seite
Andreas B. schrieb:
> 0x70000000 =  1879048192
> 0x90000000 = -1879048192
> 0x70000000 + 0x90000000 = 0x100000000
Also gibt 1879048192 + -1879048192 = 0
Ein Übertrag ist vollkommen uninteressant, und muß nicht extra behandelt 
werden.

Kurz: wenn eine positive un eine negative Zahl addiert wird, kann (für 
das Ergebnis) kein Überlauf passieren. Und dann muß auch kein Überlauf 
behandelt werden.
Gast
Ich hätte noch eine Frage, die ganz ähnlich ist, deshalb wollte ich da 
erstmal keinen neuen Thread starten.
Ich habe:
1
signed long int a,b;
2
a = bla;
3
b = blub;
4
a += b; // wie den Überlauf/Vorzeichenwechsel hier abfangen? 
5
a -= b; // Neue Variable a_alt einführen?
Gast
Wenn der Compiler etwa einen Sprung ans Ende des Programmes plaziert 
oder einen Rücksprung ins Betriebssystem (exit, abort, return, trap, 
int, ...), dann ist das Programm für meine Verhältnisse dort zu Ende.

Oder möchtest du jetzt Haare spalten?
Gast
Karl heinz Buchegger schrieb:
> Bastelmaus schrieb:
>> Ich hätte noch eine Frage, die ganz ähnlich ist, deshalb wollte ich da
>> erstmal keinen neuen Thread starten.
>
> Und welchen der vielen Vorschläge von weiter oben hast du nicht
> verstanden?

Lieber Karl heinz Buchegger,  :-)
ich denke ich habe den Vorschlag von Lothar Miller schon verstanden,
und bin auch drauf gekommen, das man auch den Fall berücksichtigen 
sollte, das b und c = -2147483648 sind.
Dann ist das falsche Ergebnis nämlich 0  :-(
Dies kann mit der Abfrage if (a>=0 ... korrigiert werden.  :-)
1
  signed long int a,b,c;
2
  b = -2147483648;
3
  c = -2147483648;
4

5
  a = b + c;
6
  if (a<0 && b>0 && c>0) a=0x7FFFFFFF;
7
  if (a>=0 && b<0 && c<0) a=0x80000000;

Meine neue Frage bezieht sich darauf, wie man es am besten macht, wenn 
man nicht a = b + c berechnen will, sondern a += b;
Ist es dann schlau, vor der Addition eine Kopie a_alt von a zu machen?
1
  signed long int a,a_alt,b;
2
  a = bla;
3
  b = blub;
4

5
        a_alt = a; // a_alt ist eine Kopie von a
6
  a += b;
7
  if (a<0 && b>0 && a_alt>0) a=0x7FFFFFFF;
8
  if (a>=0 && b<0 && a_alt<0) a=0x80000000;
Oder gibt es da noch einen Zaubertrick?  ;-)

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 15 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.