mikrocontroller.net

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


Autor: Bjoern B. (kuen)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Matthias Lipinsky (lippy)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja.

Autor: Unbekannter (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Gast (Gast)
Datum:

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

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Rufus Τ. Firefly (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht 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...

Autor: P.M. (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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 ;)

Autor: Willi Wacker (williwacker)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Tcf Kat (tcfkat)
Datum:

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

Autor: Matthias Lipinsky (lippy)
Datum:

Bewertung
0 lesenswert
nicht 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 ;-)

Autor: Tcf Kat (tcfkat)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bytes. And I bite you! ;)

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

Autor: Andreas K. (a-k)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Simon K. (simon) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wer portabel sein will, benutzt garkein char, sondern einen uint8_t oder 
int8_t.

Autor: Marius S. (lupin) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Tcf Kat (tcfkat)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wer portabel sein will, definiert sich per sizeof() seine eigenen 
Datentypen...

Autor: Simon K. (simon) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Simon K. (simon) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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__...
Since these typedefs are mandated by the C99 standard, they are preferred
over rolling your own typedefs.

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Willi Wacker (williwacker)
Datum:

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

Autor: Andreas K. (a-k)
Datum:

Bewertung
0 lesenswert
nicht 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)?

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht 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...)

Autor: Andreas K. (a-k)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Andreas K. (a-k)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Andreas K. (a-k)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: let (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht 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...

Autor: Christian U. (z0m3ie)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: horst (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ein für alle mal
es läuft über

ende der diskussion!

Autor: Andreas K. (a-k)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Christian U. (z0m3ie)
Datum:

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

OK, das ist klar.
Danke.

Autor: Uhu Uhuhu (uhu)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Uhu Uhuhu (uhu)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Andreas K. (a-k)
Datum:

Bewertung
0 lesenswert
nicht 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

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.