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?
> 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.
du wirst einem char nie den Wert 255 zuweisen können, wenn dann einem unsigned char...
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.
> 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.
@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...
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 ;)
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.
>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 ;-)
Bytes. And I bite you! ;) sizeof(char)=1 ist sogar eine olle K&R-Definition, alles andere ist implementationsabhängig.
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.
Wer portabel sein will, benutzt garkein char, sondern einen uint8_t oder int8_t.
Und wie sind uint8_t und int8_t definiert? Als signed oder unsigned char - oder etwa nicht? Das sind ja keine standard C Typen.
Wer portabel sein will, definiert sich per sizeof() seine eigenen Datentypen...
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.
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. |
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.
hast Dich in der Aufregung vertippt, natürlich: 0..255 und das sind 256 verschiedene Werte
@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)?
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...)
> 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.
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.
> 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.
>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
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...
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.
> 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.
>>if (index+1 == 0) //nein, 256 (bei -mint8: 0) >>Insofern ist bei solchen Tricks Vorsicht geboten. OK, das ist klar. Danke.
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.
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.
> 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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.