www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Überlauf macht Vorzeichenwechsel


Autor: Bastelmaus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,
ich hätte mal ein Problem beim C Programmieren:
unsigned long int a,b,c;

b = blablub 
c = blubbla

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?

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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?

Autor: Frank Buss (foobar)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Michael G. (linuxgeek) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Frank Buss (foobar)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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 
:-)

Autor: Bastelmaus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bastelmaus schrieb:
> unsigned long int a,b,c;

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

b = blablub 
c = blubbla

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?

Autor: Thomas Eckmann (Firma: Thomas Eckmann Informationst.) (thomase)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Was ist denn jetzt das Problem?

Einen Überlauf bei zwei positiven Zahlen hast Du, wenn das Ergebnis(a) 
kleiner ist als der größere der beiden Operanden(b,c).

Mfg

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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:
  signed long int a,b,c;

  b = blablub 
  c = blubbla

  a = b + c;
  if (a<0 && b>0 && c>0) a=0x7fffffff;
  if (a>0 && b<0 && c<0) a=0x80000000;

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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 ...

Autor: Bastelmaus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Lothar Miller schrieb:
> a = b + c;
> if (a<0 && b>0 && c>0) a=0x7fffffff;
> 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?

Autor: Jens G. (jensig)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
a = 0 ist doch kein Überlauf, sondern bedeutet nur, daß |+b|=|-c| (oder 
umgekehrt) war.

Autor: Bastelmaus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jens G. schrieb:
> a = 0 ist doch kein Überlauf, sondern bedeutet nur, daß |+b|=|-c| (oder
> umgekehrt) war.

Ja eben nicht,
wenn z.B.
b = 0x70000000;
c = 0x90000000;
a = b + c; //Jetzt kommt meine Rakete vom Kurs ab :-(

Autor: Andreas B. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bastelmaus schrieb:
> Ja eben nicht,
> wenn z.B.
b = 0x70000000;
c = 0x90000000;
a = b + c; //Jetzt kommt meine Rakete vom Kurs ab :-(

Angenommen 32 Bit vorzeichenbehaftete Variablen ist das doch exakt der 
Fall

Jens G. schrieb:
> |+b|=|-c|

Also wieso "eben nicht"?

Autor: Jens G. (jensig)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bastelmaus schrieb:
> Ja eben nicht,
> wenn z.B.

>b = 0x70000000;
>c = 0x90000000;
>a = b + c; //Jetzt kommt meine Rakete vom Kurs ab :-(

Wie soll da a=0 rauskommen? Ich verstehe die Spezialität mit a=0 nicht 
:-(

Autor: Andreas B. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Bastelmaus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Man muß noch einen Fall berücksichtigen:
0x80000000 + 0x80000000

Autor: Bastelmaus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich hätte noch eine Frage, die ganz ähnlich ist, deshalb wollte ich da 
erstmal keinen neuen Thread starten.
Ich habe:
signed long int a,b;
a = bla;
b = blub;
a += b; // wie den Überlauf/Vorzeichenwechsel hier abfangen? 
a -= b; // Neue Variable a_alt einführen?

Autor: Haku (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Es ist aber in der Tat so:
Überlauf bei vorzeichenbehafteten Ganzzahlen ist undefiniertes 
Verhalten. Der Prozessor darf sich erhängen, der Compiler darf das 
Programm beenden und so weiter.

Siehe dazu:
https://www.securecoding.cert.org/confluence/displ...

Autor: Simon K. (simon) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Der Compiler darf das Programm beenden? Ja ne is klar!

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Simon K. schrieb:
> Der Compiler darf das Programm beenden? Ja ne is klar!

Auf einer Z80 würde das gehen. Der hat eine HALT Instruktion. Danach 
macht die CPU nichts mehr :-)
Der Compiler könnte die für den Fall des Falles einbauen. Indirekt hat 
er damit das Programm beendet :-)

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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?

Autor: Haku (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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?

Autor: Bastelmaus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.  :-)
  signed long int a,b,c;
  b = -2147483648;
  c = -2147483648;

  a = b + c;
  if (a<0 && b>0 && c>0) a=0x7FFFFFFF;
  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?
  signed long int a,a_alt,b;
  a = bla;
  b = blub;

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

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.