Das Programm zählt munter von 0 bis 499. Warum bekomme ich keine
negativen Zahlen? Wenn ich uint8_t nehme zählt er doch auch nur bis 255
und fängt dann wieder bei 0 an!
Gruß Dennis
Das Überlaufverhalten von Integern ist in C undefiniert. Bei
vorzeichenlosen Integern gibt es keine Überläufe, weil dort immer modulo
größtmoglicher Wert gerechnet wird.
Der Überlauf ist ein Flag .
Am besten Wert austesten in der Schleife etwa:
if (Zahl == 256 ) {Überlauf = true;}
Könne auch sein das der Compiler eine Einstellung hat, dann den
Programmablauf zu unterbrechen.
Hmm... ganz verstehe ich das nicht: Der größtmögliche Wert ist hier doch
+127. Wenn ich irgendwas Modulo n nehme, kann es doch nicht größer als n
werden!?
Fakt ist doch: int8_t hat 8 Bit.. wie bekomme ich in 8 Bit die Zahl 499
rein?
Gruß Dennis
Welcher compiler ist das?
Auch wenn das Überlaufverhalten von signed Werten nicht spzifiziert ist,
ist es IMHO nicht korrekt wenn du da Zahlen von 0 bis 499 für einen
int8_t siehst.
Auf was für einer Platform probierst du das denn aus?
Auf meinem PC (Win7, visual Studio 2012) bekomme ich den Überlauf, also
zahlen von -128 bis +127.
Ich denke es könnte an deinem int8_t liegen.
Es wird wohl ein Typedef auf char sein. Wenn es wirklich "char" und
nicht auf "signed char" ist, dann könnte es sein, dass dein Compiler den
"char" per default als "unsigned" behandelt. (Das ist zum Beispiel
Standardeinstellung beim Atmel Studio.)
Das würde dann auch erklären warum du keinen "Überlauf" bekommst.
Grüße
, leider bin ich gerade zu blöd die Header-Datei auf der Festplatte zu
finden... :-/ Aber danke schonmal, dann habe ich etwas wo ich weiter
forschen kann!
Kaj schrieb:> Ich denke es könnte an deinem int8_t liegen.> Es wird wohl ein Typedef auf char sein. Wenn es wirklich "char" und> nicht auf "signed char" ist, dann könnte es sein, dass dein Compiler den> "char" per default als "unsigned" behandelt.
Das setzt freilich voraus, dass int8_t nicht durch ein zum Compiler
passendes Include-File definiert wurde.
Das Verhalten ist mit GCC/Linux 4.7.3 reproduzierbar und tritt nur bei
eingeschalteter Optimierung auf, nicht aber bei fwrapv.
Das Verhalten des Compilers ist völlig in Ordnung, da - wie schon
erwähnt wurde - das Überlaufverhalten undefiniert ist. Folglich ist bei
Code, der Überlauf erzeugt, jedes beliebige Ergebnis zulässig.
Hintergrund: Code ist mit Wortbreite oft effizienter als mit Bytes.
Karl Heinz Buchegger schrieb:> Welcher compiler ist das?>> Auch wenn das Überlaufverhalten von signed Werten nicht spzifiziert ist,> ist es IMHO nicht korrekt wenn du da Zahlen von 0 bis 499 für einen> int8_t siehst.
Es wäre ungewöhnlich, aber korrekt ist es schon. "undefined behiavior"
halt.
A. K. schrieb:> Das Verhalten ist mit GCC/Linux 4.7.3 reproduzierbar und tritt nur bei> eingeschalteter Optimierung auf, nicht aber bei fwrapv.>> Das Verhalten des Compilers ist völlig in Ordnung, da - wie schon> erwähnt wurde - das Überlaufverhalten undefiniert ist. Folglich ist bei> Code, der Überlauf erzeugt, jedes beliebige Ergebnis zulässig.>> Hintergrund: Code ist mit Wortbreite oft effizienter als mit Bytes.
Tatsache, ich habe das Programm jetzt einmal mit und einmal ohne -O2
kompiliert und es ist wie du es beschreibst.
Aber dann stellt sich mir doch die Frage: wenn ich mich nicht drauf
verlassen kann, dass int8_t 8 Bit groß ist, warum soll ich es dann
benutzen!?
Gruß Dennis
Dennis S. schrieb:> Aber dann stellt sich mir doch die Frage: wenn ich mich nicht drauf> verlassen kann, dass int8_t 8 Bit groß ist, warum soll ich es dann> benutzen!?
Im Speicher ist es 8 Bit gross. Nur ist es hier bei Optimierung nicht im
Speicher, sondern in einem Prozessorregister. Ein Prozessorregister nur
teilweise zu verwenden ist oft nachteilig, sofern überhaupt möglich.
Dennis S. schrieb:> Das Programm zählt munter von 0 bis 499. Warum bekomme ich keine> negativen Zahlen?
Wenn deine Variable 'zahl' ohne Murren den Zählerstand 499 abbilden
kann, sprich alles dafür, dass int8_t kein 8-Bit Datentyp ist.
Unabhängig von irgendwelcher Vorzeicheninterpretation.
So ist das halt, manchmal ist denkt sich der Entwickler des Compilers
etwas anderes, als der Entwickler des Programms.
Wenn es dem Entwickler des Programmes es ganz egal ist, was bei einem
Überlauf passiert, warum soll der Compilereentwickler irgenderwas
vorschreiben?
Wolfgang schrieb:> Dennis S. schrieb:>> Das Programm zählt munter von 0 bis 499. Warum bekomme ich keine>> negativen Zahlen?>> Wenn deine Variable 'zahl' ohne Murren den Zählerstand 499 abbilden> kann, sprich alles dafür, dass int8_t kein 8-Bit Datentyp ist.>> Unabhängig von irgendwelcher Vorzeicheninterpretation.
Der Compiler macht (mit -O2) das hier aus der Schleife:
1
L2:
2
movl%ebx,4(%esp)
3
movl$LC0,(%esp)
4
call_printf
5
incl%ebx
6
cmpl$500,%ebx
7
jneL2
So wie es aussieht fasst er die beiden Variablen zusammen und hält sie
in einem 32 Bit Register.
Interessanterweise gibt das Programm -12 aus wenn man "zahl" nach der
Schleife ausgibt (auch mit Optimierung). Wenn man sich den Code
anschaut, dann sieht man das der Compiler den Wert vorher ausgerechnet
hat und einfach als Konstante ausgibt.
Wolfgang schrieb:> Wenn deine Variable 'zahl' ohne Murren den Zählerstand 499 abbilden> kann, sprich alles dafür, dass int8_t kein 8-Bit Datentyp ist.
Doch.
Und für jene, die es immer noch nicht kapiert haben: Wenn "zahl" zu
uint8_t wird, dann gibts am Schluss statt 499:
237
238
239
240
241
242
243
Ohne -fwrapv gibts eben wirklich nur bei vorzeichenlosen Typen das
intuitiv erwartete Überlaufverhalten. Sonst gilt Schrott rein Schrott
raus.
Mike schrieb:> So wie es aussieht fasst er die beiden Variablen zusammen und hält sie> in einem 32 Bit Register.
Dieser Schritt lässt sich auch abschalten:
gcc -O2 -fno-ivopts ...
"Perform induction variable optimizations (strength reduction, induction
variable merging and induction variable elimination) on trees."
Sinn: http://www.compileroptimizations.com/category/ive.htm
Dennis S. schrieb:> int main(void) {>> int8_t zahl = 0;> int16_t n = 0;>> for (n=0; n<500; n++){> printf("%3d\n", zahl++);> }>> return 0;> }
Ich würde das einfach so lösen:
int8_t zahl = -128;
int16_t n = 0;
for (n=0; n<500; n++){
printf("%3d\n", zahl++);
if (Zahl>127) Zahl=-128; // der Porgrammierer weiß was er will bei einem
Überlauf könnte allesmögliche sein,hängt von der Anwendung ab
}
return 0;
}
lutz h. schrieb:> if (Zahl>127) Zahl=-128;
;-)
gcc: "Warnung: Vergleich ist durch beschränkten Wertebereich des
Datentyps stets »unwahr« [-Wtype-limits]"
A. K. schrieb:> Doch.
Nein. Ein 8-Bit Datentyp kann wahlweise den Zahlenbereich [0..255] oder,
bei 2er-Komplementdarstellung [-128..+127], aufnehmen. Mehr nicht.
Welche Bitkombination würdest du denn vorschlagen, um dein "Doch" zu
untermauern? Wie sähe nach deiner Meinung z.B. die Zahl 496 im
Dualsystem, in 8 Bit untergebracht, aus?
Warum sollte 496 in dem hier diskutierten Fall in einem int8_t
darstellbar sein? Der Wert 496 entsteht nach einem Signed Overflow, und
der ist in C "Undefined Behaviour" und wird auch von der Implementation
(hier: avr-gcc) nicht näher definiert -- zumindest nicht ohne Schalter
wie z.B. -fwrapv.
Wolfgang schrieb:> Welche Bitkombination würdest du denn vorschlagen, um dein "Doch" zu> untermauern?
Ganz einfach. Ein int8_t ist 8 Bit breit. Ein Compiler, der keine 8 Bit
Typen kennt, kennt auch nicht den Typ int8_t, per Definition.
Aber: Der Compiler verwendet für diese Variable effektiv nicht den Typ
int8_t, obwohl es im Quelltext so drinsteht. Solange im Rahmen der C
Spezifikation das gleiche Ergebnis rauskommt darf er das nämlich. Da
dieser Code aber die C Spezifikation verletzt, hat der Compiler einige
Freiheiten. Und die nimmt er sich.
eine Zahl kann auch in der Form a*x + b dargestellt werden.
mit b = 495 definiert als Konstante und und x = 1 definiert als
Konstante wäre die binäre Darstellung von 496 : a= 0000 0001.