Forum: Compiler & IDEs Überlauf von int, char etc.


von Thomas (Gast)


Lesenswert?

Hallo,
ist eigentlich im C-Standard festgelegt, was bei einem Überlauf der
verschiedenen Datentypen als nächster Wert herauskommt?
Also was für ein Wert erhalte ich nach einem Überlauf durch z.b. i++
bei:

int
unsigned int
char
unsigned char

Ich brauche in einem Timerinterrupt einen Zähler der immer durchläuft.
Oder sollte man des Stils wegen auf die Einhaltung des Wertebereichs
prüfen und dann manuell wieder von vorn beginnen?

von Wolfgang Horn (Gast)


Lesenswert?

Hi, Thomas,

wenn Du aufwärts zählst und am Ende des Wertebereiches angekommen bist,
dann führt der nächste Schritt ans andere Ende.

Srell Dir den Wertebereich wie das Zifferblatt einer Uhr vor - nach 23
Uhr kommt 0 Uhr.

Dein Zähler läuft also sowieso immer durch.

Gelegentlich kann man Überlauf nicht brauchen. Dann nehme ich zwei
Variablen, die ich beide auf diesem Ziffernblatt um 90° versetzt
weiterzähle.

Ciao
Wolfgang Horn

von Rolf Magnus (Gast)


Lesenswert?

> ist eigentlich im C-Standard festgelegt, was bei einem Überlauf
> der verschiedenen Datentypen als nächster Wert herauskommt?

Bei vorzeichenlosen ja. Da werden alle Berechnungen immer Modulo
2 hoch Bitzahl durchgeführt. Wenn man oben rausläuft, kommt man unten
wieder rein. Bei den Typen mit Vorzeichen ist es undefiniert.

> Also was für ein Wert erhalte ich nach einem Überlauf durch z.b.
> i++ bei:
>
> int

undefiniert

> unsigned int

0

> char

implementationsspezifisch

> unsigned char

0

von A.K. (Gast)


Lesenswert?

"ist eigentlich im C-Standard festgelegt, was bei einem Überlauf der
verschiedenen Datentypen als nächster Wert herauskommt?"

Ber Typen ohne Vorzeichen ja. Modulo (<maximaler Wert>+1). Ist das was
man intuitiv auch erwartet.

Bei Typen mit Vorzeichen ist das Verhalten bei Überlauf offiziell
undefiniert.

von peter dannegger (Gast)


Lesenswert?

Noch ne Gemeinheit, bei int ist die Länge undefiniert.

Statt int sollte man daher besser short (16Bit) nehmen, da auf
32Bittern int = long (32Bit) ist.


Peter

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

> Noch ne Gemeinheit, bei int ist die Länge undefiniert.

Generell ist bei allen ,,allgemeinen Typen'' die Länge undefiniert.
Es gibt nur Mindestanforderungen an die Genauigkeit, die bei unseren
üblichen Zweierkomplementdarstellungen und IEEE754-Gleitkommazahlen
folgendes implizieren:

. sizeof(char) >= 8
. sizeof(short) >= 16
. sizeof(int) >= 16
. sizeof(long) >= 32
. sizeof(long long) >= 64
. sizeof(float) >= 32
. sizeof(double) > 32

(Letzteres wird vom AVR-GCC derzeit nicht eingehalten.)

> Statt int sollte man daher besser short (16Bit) nehmen, da auf
> 32Bittern int = long (32Bit) ist.

Nein, wenn man Typen mit expliziten Längen haben möchte, sollte man
auch Typen mit expliziten Längen benutzen, statt implizite Annahmen
zu treffen.  Diese sind (per C99) in <stdint.h> definiert.  Wenn eine
Maschine dann z. B. keinen 8-Bit-Datentyp kennt (soll's bei einigen
DSPs geben), dann bekommt man wenigstens saubere Fehler beim Versuch,
int8_t oder uint8_t zu benutzen (die gibt's dort dann nicht), statt
irgendwelcher Überraschungen, weil der Programmierer implizit
angenommen hat, dass sein "unsigned char" genau 8 Bits lang wäre und
von 255 nach 0 umschlägt.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Immerhin gibt es auch eine Headerdatei, die die Grenzen der vor C99
definierten Datentypen beschreibt - limits.h

Auszug aus limits.h des mit Rowley Crossworks for ARM gelieferten gcc:
1
#define CHAR_BIT   8
2
#define CHAR_MAX   255
3
#define CHAR_MIN   0
4
#define SCHAR_MAX  127
5
#define SCHAR_MIN  (-128)
6
#define UCHAR_MAX  255
7
#define SHRT_MAX   32767
8
#define SHRT_MIN   (-32767 - 1)
9
#define USHRT_MAX  65535
10
11
#if defined(__CROSSWORKS_MSP430) || defined(__CROSSWORKS_AVR) ||
12
defined(__CROSSWORKS_MAXQ)
13
#define INT_MAX   32767
14
#define INT_MIN   (-32767 - 1)
15
#define UINT_MAX  65535
16
#else
17
#define INT_MAX    2147483647
18
#define INT_MIN     (-2147483647 - 1)
19
#define UINT_MAX   4294967295
20
#endif
21
22
#define LONG_MAX   2147483647
23
#define LONG_MIN   (-2147483647 - 1)
24
#define ULONG_MAX  4294967295
25
#define LLONG_MIN  (-9223372036854775807LL - 1)
26
#define LLONG_MAX  9223372036854775807LL
27
#define ULLONG_MAX 18446744073709551615ULL

Damit kann man sich also auch mit nicht-C99-Compilern behelfen; eine
vergleichbare Datei existiert beispielsweise auch bei MS-Compilern, die
älter sind als C99.

von Rolf Magnus (Gast)


Lesenswert?

> Noch ne Gemeinheit, bei int ist die Länge undefiniert.

Sie ist nicht undefiniert, sondern implementationsspezifisch.

> Statt int sollte man daher besser short (16Bit) nehmen, da auf
> 32Bittern int = long (32Bit) ist.

short und long sind genauso implementationsspezifisch wie int.


Zur Ergänzung von Rufus' Posting:

C99 bietet mit stdint.h einen Header, der typedefs unter anderem für
Integertypen mit festen Größen bietet.
Es ist übrigens ein Armutszeugnis für die Compilerhersteller, wenn sie
es nach 7 Jahren immer noch nicht geschafft haben, halbwegs
ISO-konforme Compiler zu bauen. C89 ist keine Norm, denn es wurde mit
Erscheinen von C99 offiziell ungültig.

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.