Warum bekomme ich keinen Überlauf?!

OP #3365674
Hallo zusammen,

ich habe folgenden Code:
1
#include <stdio.h>
2
#include <stdint.h>
3

4
int main(void) {
5

6
int8_t zahl = 0;
7
int16_t n = 0;
8

9
    for (n=0; n<500; n++){
10
        printf("%3d\n", zahl++);
11
    }
12

13
return 0;
14
}

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
Gast #3365685
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.
OP #3365691
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
Gast #3365705
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
OP #3365720
Der verwendete Compiler ist
1
gcc (Ubuntu/Linaro 4.7.2-2ubuntu1) 4.7.2
, 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!
#3365833
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.
#3365837
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.
Gast #3365854
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.
OP #3365856
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
#3365858
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.
Gast #3366021
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.
#3366024
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?
Gast #3366033
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
  jne  L2

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.
#3366046
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.
1
#include <stdio.h>
2
#include <stdint.h>
3

4
int main(void) {
5

6
int8_t zahl = 0;
7
int16_t n = 0;
8
    for (n=0; n<500; n++){
9
        printf("%3d\n", zahl++);
10
    }
11
    printf("Size: %d\n", sizeof zahl);
12

13
return 0;
14
}
gibt:

496
497
498
499
Size: 1
#3366048
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.
#3366072
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;
 }
Gast #3366733
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?
#3366804
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.

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 13 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.