Hallo,
ich hätte mal ein Problem beim C Programmieren:
1
unsignedlonginta,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?
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
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
:-)
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
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:
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 ...
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?
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
:-(
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.
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.
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 :-)
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?
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?
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
signedlonginta,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?