Forum: Mikrocontroller und Digitale Elektronik Überlauf bei 255 + 1?


von Bjoern B. (kuen)


Lesenswert?

Hallo,

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?

von Matthias L. (Gast)


Lesenswert?

Ja.

von Unbekannter (Gast)


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.

von Gast (Gast)


Lesenswert?

du wirst einem char nie den Wert 255 zuweisen können, wenn dann einem 
unsigned char...

von Johannes M. (johnny-m)


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.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

> Eine char-Variable hat per Definition einen Wertebereich von -128 bis
> +127.

Nur wenn char == signed char.

Das lässt sich bei den meisten Compilern per Kommandozeilenoption 
konfigurieren.

Man sollte sich daher NICHT darauf verlassen, daß char 
vorzeichenbehaftet bzw. nicht vorzeichenbehaftet ist.

von Johannes M. (johnny-m)


Lesenswert?

@Rufus:
Klar, aber standardmäßig ist es schon so. Ist eigentlich traurig genug, 
dass es da solch verwerfliche Möglichkeiten gibt, die die Portierbarkeit 
von Code doch sehr einschränken. Aber das Thema hatten wir hier afair 
unlängst auch schon mal...

von P.M. (Gast)


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 ;)

von Willi W. (williwacker)


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.

von Tcf K. (tcfkat)


Lesenswert?

Dafür gibt es sizeof(). Wobei sizeof(char) per C-Definition 1 ist.

von Matthias L. (Gast)


Lesenswert?

>Wobei sizeof(char) per C-Definition 1 ist.

Ja, aber eins was? Welche Einheit steht dahinter..

Somit beißt sich die Katze in ihren Schwanz ;-)

von Tcf K. (tcfkat)


Lesenswert?

Bytes. And I bite you! ;)

sizeof(char)=1 ist sogar eine olle K&R-Definition, alles andere ist 
implementationsabhängig.

von Andreas K. (a-k)


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.

von Simon K. (simon) Benutzerseite


Lesenswert?

Wer portabel sein will, benutzt garkein char, sondern einen uint8_t oder 
int8_t.

von Marius S. (lupin) Benutzerseite


Lesenswert?

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

von Tcf K. (tcfkat)


Lesenswert?

Wer portabel sein will, definiert sich per sizeof() seine eigenen 
Datentypen...

von Simon K. (simon) Benutzerseite


Lesenswert?

Tcf Kat wrote:
> Wer portabel sein will, definiert sich per sizeof() seine eigenen
> Datentypen...

Hä? Dafür ist doch der Header stdint.h zuständig, der die Typen 
(u)intx_t definiert.

von Simon K. (simon) Benutzerseite


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.

von Gast (Gast)


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.

von Willi W. (williwacker)


Lesenswert?

hast Dich in der Aufregung vertippt, natürlich: 0..255 und das sind 256 
verschiedene Werte

von Andreas K. (a-k)


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)?

von Johannes M. (johnny-m)


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...)

von Andreas K. (a-k)


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.

von Andreas K. (a-k)


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.

von Andreas K. (a-k)


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.

von let (Gast)


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

von Johannes M. (johnny-m)


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...

von Christian U. (z0m3ie)


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.

von horst (Gast)


Lesenswert?

ein für alle mal
es läuft über

ende der diskussion!

von Andreas K. (a-k)


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.

von Christian U. (z0m3ie)


Lesenswert?

>>if (index+1 == 0)  //nein, 256 (bei -mint8: 0)
>>Insofern ist bei solchen Tricks Vorsicht geboten.

OK, das ist klar.
Danke.

von Uhu U. (uhu)


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.

von Uhu U. (uhu)


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.

von Andreas K. (a-k)


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.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.