Überlauf bei 255 + 1?

Gast #657097
Lesenswert?

> was passiert wenn ich einer mit "char" deklarierten Variablen die
> den Wert 255 besitzt eine 1 hinzuaddiere?

Es geht um 'C'?

Das Verhalten ist undefiniert. Es darf alles passieren, von überhaupt 
nichts über Programmsabsturz bis zur Atombombenexplosion.


> Gibt es einen Überlauf und der wert wird 0?

Bei den meisten Implementierungen könnte das so sein.
#657106
Lesenswert?

Bjoern B. wrote:
> was passiert wenn ich einer mit "char" deklarierten Variablen die den
> Wert 255 besitzt eine 1 hinzuaddiere? Gibt es einen Überlauf und der
> wert wird 0?
Eine char-Variable hat per Definition einen Wertebereich von -128 bis 
+127. Sie kann also nicht den Wert "255" enthalten... Sie kann 
allerdings den Wert 0xFF enthalten (der unter Vernachlässigung der 
Zweierkomplement-Darstellung den Wert "255" repräsentiert). Wenn Du da 
eine "1" hinzuaddierst, dann gibt es tatsächlich einen sogenannten 
Überlauf.
Gast #657122
Lesenswert?

Naja, im Endeffekt ist es ja sache des Programmierers.
Wenn er es vernünftig und portierbar heben will schreibt er halt immer 
"signed char" bzw "unsigned char" (genau so bei allen anderen Typen 
auch) und schon ist alles bestens.
Der Fehler sitzt halt doch immer vor dem PC ;)
#657287
Lesenswert?

Portierbar auch nur solange char (signed oder unsigned) dieselbe Breite 
hat. Wenn Du eine Software schreibst, die davon ausgeht, dass Dein char 
8bit breit ist, magst Du Probleme bei der Portierung auf andere Systeme 
mit einer Breite von 16bit bekommen.

Sonst wäre es auch zu einfach und jeder könnte es.
#657439
Lesenswert?

Bei Datentypen mit Vorzeichen ist das Verhalten undefiniert.

Bei Datentypen ohne Vorzeichen hingegen ist Modulo-Arithmetik definiert. 
Es ist zwar nirgends vorgeschrieben, dass 255+1 unbedingt 0 ergibt, weil 
ein "unsigned char" ja nach Implementierung auch den Wert 256 enthalten 
darf, aber wenn ein Datentyp nur die Werte 0..255 enthalten kann, dann 
folgt auf 255 zwingend die 0.
Persönliche Seite #657465
Lesenswert?

Marius Schmidt wrote:
> Und wie sind uint8_t und int8_t definiert? Als signed oder unsigned char
> - oder etwa nicht? Das sind ja keine standard C Typen.

uint8_t wird wohl ein unsigned int mit 8 bit sein. ein int8_t wird ein 
signed int mit 8 bit sein.

Standard-C Typen nicht, aber gerade, wenn man von einer bestimmten Größe 
der Variable in Bytes ausgehen muss, sind diese Typen oft gesehen.

Edit:
http://www.nongnu.org/avr-libc/user-manual/group__avr__stdint.html
1
Since these typedefs are mandated by the C99 standard, they are preferred
2
over rolling your own typedefs.
Gast #657566
Lesenswert?

Ihr solltet alle mal über den Tellerrand schauen, und dabei in die 
Assembler-Ecke und auch die µC Architektur. Was macht ein Assembler 
"ADD" bei einem Überlauf.

@Andreas
> weil ein "unsigned char" ja nach Implementierung auch den Wert 256
> enthalten darf

Wo hast du den Blödsinn denn her? Ein unsigned char kann zwar 256 
verschiedene Werte annehmen, aber das sind die werte 0-256.
#657632
Lesenswert?

@Willi:

> Wo hast du den Blödsinn denn her? Ein unsigned char kann zwar 256
> verschiedene Werte annehmen, aber das sind die werte 0-256.

Danke für die Blumen, aber m.W. darf man auch einen Compiler schreiben, 
in dem sizeof(char) == sizeof(short) == sizeof(int) == sizeof(long) == 1 
gilt, z.B. wenn man es mit einer streng wortadressierenden Maschine zu 
tun hat. ANSI definiert nur Mindestvoraussetzungen.

Ich nehme an, auch Dezimaldarstellung mit einem Wertebereich von 0-999 
wäre für "char" zulässig. Sowas ist aber etwas aus der Mode gekommen 
(kennt jemand hier noch Donald Knuths MIXv1)?
#657636
Lesenswert?

Andreas Kaiser wrote:
> ...aber m.W. darf man auch einen Compiler schreiben,
> in dem sizeof(char) == sizeof(short) == sizeof(int) == sizeof(long) == 1
> gilt, z.B. wenn man es mit einer streng wortadressierenden Maschine zu
> tun hat.
Der darf sich dann aber nicht mehr ANSI-C-Compiler nennen, weil int 
afaik mindestens 16 Bit haben muss, und zwar plattformunabhängig...

Mein Wissensstand ist:
sizeof(char) == 1
sizeof(int) >= 2 ("natürliche Breite" der Maschine, aber mind. 16 Bit)
sizeof(short) <= sizeof(int)
sizeof(long) > sizeof(int) (Da bin ich mir grad nicht 100%ig sicher, ob 
da auch ein ">=" hinmuss, aber ich meine, mich zu erinnern, dass es 
explizit heißt "long ist immer größer als int")
Wenn jemand da (neuere/abweichende) Infos hat, immer her damit (wenns 
geht mit Quelle...)
#657649
Lesenswert?

> Der darf sich dann aber nicht mehr ANSI-C-Compiler nennen, weil int
> afaik mindestens 16 Bit haben muss, und zwar plattformunabhängig...

Man nehme eine Maschine, deren Register und Speicher aus 36bit Worten 
besteht. Und die genau und nur 36bit Worte verarbeiten kann, keine 
Bytes, keine Halbworte.

Dann wäre es m.E. zulässig, aus Performancegründen ein solches 36bit 
Wort als Grundeinheit zu definieren. Der von ANSI verlangte Wertebereich 
wäre damit (über-) erfüllt.

Ein anderer Implementor mag statt dessen aus Platzgründen 9bit Bytes 
erfinden, zu Lasten der Laufzeit. Dann wäre der Wertebereich von 
"unsigned char" 0..511.

> explizit heißt "long ist immer größer als int")

Dann wäre kaum ein Compiler für 32bit Maschinen ANSI-konform, denn dort 
gilt meistens sizeof(int)==sizeof(long). Ebenso Microsofts 
Maschinenmodell für AMD64.

Mein Kennstnisstand:
sizeof(short) <= sizeof(int) <= sizeof(long)
Ob für sizeof(char) auch eine solche Relation besteht, weiss ich grad 
nicht.
#658116
Lesenswert?

C99 Rationale (v5.10): "Thus, for instance, on a machine with 36-bit 
words, a byte can be defined to consist of 9, 12, 18, or 36 bits, these 
numbers being all the exact divisors of 36 which are not less than 8." 
(byte == char, A.K.)

C89 Reference (http://www-ccs.ucsd.edu/c/types.html):
sizeof(char) <= sizeof(short) <= sizeof(int) <= sizeof(long)
Sieh dort auch für Mindest(!)anforderungen an die Wertebereiche.
#658128
Lesenswert?

> Ihr solltet alle mal über den Tellerrand schauen, und dabei in die
> Assembler-Ecke und auch die µC Architektur. Was macht ein Assembler
> "ADD" bei einem Überlauf.

Den Ball mit dem Tellerrand kann ich dir zurück spielen. Bei manchen 
RISCs (z.B. MIPS) gibt's bei ADD dann einen Overflow-Trap. Weshalb es 
zusätzlich ein ADDU gibt, der dies nicht tut. Ein C Compiler ist dann 
frei, für Rechnung mit "signed" ADD und für Rechnung mit "unsigned" ADDU 
zu verwenden. Er darf aber auch in beiden Fällen ADDU verwenden.

Es ist somit nicht nur theoretisch sondern auch sehr praktisch 
undefiniert, was jenseits des Limits geschieht, und darf bei "int" und 
"short" verschieden sein.
Gast #658130
Lesenswert?

>sizeof(int) >= 2 ("natürliche Breite" der Maschine, aber mind. 16 Bit)

Für die "natürliche" Breite kann auch long gewählt werden.
So macht es z.B. der GCC auf 64Bit Platformen.

sizeof(int) == 4
sizeof(long) == 8
sizeof(long long) == 8
#658134
Lesenswert?

OK, meine Informationen stammen im Großen und Ganzen aus dem guten alten 
K&R (2. Auflage), der nach eigenen Angaben ANSI-C89-Standard-konform 
ist. Und da steht eben:
char    a single byte, capable of holding one character in the local
        character set

[...]
int will normally be the natural size for a particular machine. short is 
often 16 bits, long 32 bits and int either 16 or 32 bits.
[Und jetzt kommts!] Each compiler is free to choose appropriate sizes 
for its own hardware, subject only to the restriction that shorts and 
ints are at least 16 bits, longs are at least 32 bits, and short is no 
longer than int, which is no longer than long.

Das war mein Kenntnisstand. Allerdings bezieht sich der K&R natürlich 
auf Systeme, deren "natural size" ein Vielfaches von 8 Bit ist (was 
afaik auf den absoluten Löwenanteil aller Systeme zutrifft). Was der 
eigentliche Standard alles für Spielräume hinsichtlich andersartiger 
Systeme lässt, hat mich bisher nie berührt...
#662947
Lesenswert?

OK, jetzt steh ich vor dem Problem. Damit sich nicht wieder jemand unter 
informiert fühlt, es geht bei mir darum einen möglichst effizienten 
Ringbuffer zu haben effizient im Bezug auf die Ausführungszeit. Also 
dacht ich mir nehmen wir 256 byte und nen unsigned char dazu der läuft 
bei 255++ eh über.

Nun nochmal konkret die Frage die hier nach 50 Beiträgen wieder nicht 
beantwortet wurde. Läuft unsigned char auf den AVR immer über oder ist 
es hier  tatsächlich undefiniert was der GCC draus macht.
Nochmal zusammengefasst:

Compiler gcc und nur gcc
Architektur AVR und nur AVR
Datentyp unsigned char

Läuft die Variable über oder nicht ? Oder ist es undefiniert.
#662960
Lesenswert?

> Compiler gcc und nur gcc
> Architektur AVR und nur AVR
> Datentyp unsigned char

Es ist gewährleistet, dass ein Compiler, der wie WinAVR ein "unsigned 
char" als 8-Bit Byte implementiert, bei 255+1 den Wert 0 speichert. 
Eventuelle Compilerfehler aussen vor gelassen.

Für deinen Quellcode gilt das übrigens nur bedingt. Denn bei
  unsigned char index=255;
wird
  if (++index == 0)  //ja
ein anderes Ergebnis liefern als
  if (index+1 == 0)  //nein, 256 (bei -mint8: 0)
Insofern ist bei solchen Tricks Vorsicht geboten.
#662973
Lesenswert?

Undefiniert heißt bei C ganz einfach, daß das Verhalten nicht von der 
Sprache, sondern von der jeweils benutzten Hardware und dem dem 
eigentlich dem Compiler nachgeschalteten Codegenerator bestimmt wird.

Diese Vorgehensweise hält die Sprachdefinition frei von Vorschriften, 
deren Umsetzung auf bestimmten Maschinen sehr aufwendig wäre, hat aber 
auf der anderen Seite ihre Nachteile wenn es um portable Programme geht.
#662980
Lesenswert?

Andreas Kaiser wrote:
> ein anderes Ergebnis liefern als
>   if (index+1 == 0)  //nein, 256 (bei -mint8: 0)

Hier kommt die Regel zur Anwendung, daß die Operanden eines gemischten 
Ausdrucks an den größten vorkommenden Datentyp angepaßt werden. 1 hat 
den Typ int.
#662990
Lesenswert?

> Hier kommt die Regel zur Anwendung, daß die Operanden eines gemischten
> Ausdrucks an den größten vorkommenden Datentyp angepaßt werden.

Nein, eigentlich nicht. Auch
  if (index + (unsigned char)1 == (unsigned char)0)
schlägt fehl.

Es gibt die gern vergessene Regel, dass alles kleiner als "int" erst 
einmal auf "int" erweitert wird, also effektiv
  if ((int)index + (unsigned char)1 == (unsigned char)0)
daraus wird.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren