Forum: Mikrocontroller und Digitale Elektronik Char statt Integer für kleine Zahlen


von Prune (Gast)


Lesenswert?

Ahoi,

Kurze frage,

Mir geht es drum zu wissen ob es "üblich" in der uC Programmierung ist, 
dass man für kleine Zahlen den Datentyp Char statt Integer nimmt? Ich 
kann mit char ja genauso gut Ganzzahlige verarbeiten wie mit Int, nur in 
einem kleineren Wertebereich. Würde ja einiges an Speicherplatz sparen.

Wie steht ihr dazu?

von machDoch (Gast)


Lesenswert?

nimmt man nicht eher Byte statt Char? Ist ja eigentlich das gleiche aber 
irgendwie ist Byte eleganter oder

von watz (Gast)


Lesenswert?

Oder eben int8_t zumindest seit C99

von Karl M. (Gast)


Lesenswert?

Hallo,

kennst Du schon die Typen uint8_t, int8_t, uint16_t, int16_t, usw.?

Da char 8 bit sind und das Vorzeichen je nach Implementierung festgelegt 
ist.

von Stefan F. (Gast)


Lesenswert?

In der Programmiersprache C verwendet man den Datentyp uint8_t oder 
int8_t.

Allerdings verarbeiten viele 16, 32 und 64 Bit Prozessoren solch kleine 
Integer Typen langsamer, als größere Typen.

von M.K. B. (mkbit)


Lesenswert?

Ja klar macht man das. Ich würde dann aber statt char uint8_t oder 
int8_t nehmen, ist im Prinzip das Gleiche, aber es ist klarer was 
gemeint ist.

Aufpassen sollte man bei printf oder ähnlichem, weil es sonst als 
Zeichen und nicht als Zahl dargestellt wird.

von Prune (Gast)


Lesenswert?

Wenn ich unsigned char nehme dann habe ich das Vorzeichen problem doch 
nicht mehr.
Stimmt, aber byte gehört nicht zur standard C.
Hätte ich evtl erwähnen sollen, hier handelt es sich um C

von Wolfgang (Gast)


Lesenswert?

Prune schrieb:
> Wenn ich unsigned char nehme dann habe ich das Vorzeichen problem doch
> nicht mehr.

char steht für Charakter. Warum willst du diesen Datentyp unbedingt 
verwenden, wenn du 8 Bit Integer meinst und es Datentypen gibt, die 
genau dies durch die Typbezeichnung zum Ausdruck bringen?

von Prune (Gast)


Lesenswert?

Ja, Char mag wohl für Character stehen, aber das auch nur wegen dem 
Datenbereich, sonst werden die Daten ganz normal behandelt, nämlich als 
ganzzahliges.

Für mich ist unsigned char gleich dem uint8_t ?! beide von 0..255
Oder irre ich mich da komplett ? Falls ja dann bitte ich um 
Entschuldigung, aber im Moment sehe ich das nicht anders.

von Codix (Gast)


Lesenswert?

Prune schrieb:
> Für mich ist unsigned char gleich dem uint8_t ?! beide von 0..255
> Oder irre ich mich da komplett ?

Deine Annahme ist richtig.
Seit C99 ist es eben eleganter durch die Definitionen mit (u)intNN_t 
gelöst.
Gemeint ist das Gleiche.

Du kannst auch heute noch (unsigned) char schreiben anstelle von (u)int,
der Compiler macht da keinen Unterschied.

Im professionellen Umfeld würde ich das aber nicht empfehlen.

von Prune (Gast)


Lesenswert?

Achso, es geht also mehr darum dass unsigned char bzw char nicht von 
jedem Compiler gleich interpretiert wird..
Muss ich nur noch ein Header hinzufügen um uintxx_t benutzen zu können.

Vielen Dank!

von Harry L. (mysth)


Lesenswert?

Prune schrieb:
> Muss ich nur noch ein Header hinzufügen um uintxx_t benutzen zu können.

stdint.h

von A. S. (Gast)


Lesenswert?

M.K. B. schrieb:
> Aufpassen sollte man bei printf oder ähnlichem, weil es sonst als
> Zeichen und nicht als Zahl dargestellt wird.

Was meinst Du damit?

von Rolf M. (rmagnus)


Lesenswert?

Stefanus F. schrieb:
> In der Programmiersprache C verwendet man den Datentyp uint8_t oder
> int8_t.
>
> Allerdings verarbeiten viele 16, 32 und 64 Bit Prozessoren solch kleine
> Integer Typen langsamer, als größere Typen.

Deswegen nimmt man int_fast8_t bzw. uint_fast8_t. Das ist der schnellste 
Datentyp mit mindestens 8 Bit. Alternativ int_least8_t bzw. 
uint_least8_t, wenn es nicht auf Geschwindigkeit, sondern auf 
Platzverbrauch ankommt. int8_t nimmt man, wenn es essenziell ist, dass 
es exakt 8 Bit sind.

Codix schrieb:
> Prune schrieb:
>> Für mich ist unsigned char gleich dem uint8_t ?! beide von 0..255
>> Oder irre ich mich da komplett ?
>
> Deine Annahme ist richtig.

Nein, ist sie nicht. In den meisten Fällen stimmt es, aber es gibt auch 
Prozessoren, die keinen 8-Bit-Datentyp haben. Da gibt es unsigned char 
trotzdem (Vorgabe ist nur, dass es mindestens 8 Bit breit ist), aber 
keinen uint8_t.

Prune schrieb:
> Achso, es geht also mehr darum dass unsigned char bzw char nicht von
> jedem Compiler gleich interpretiert wird..

unsigned char ist immer der kleinste vorzeichenlose Typ mit mindestens 8 
Bit. signed char ist das gleiche mit Vorzeichen. Bei char für sich 
alleine ist es implementationsspezifisch, ob er ein Vorzeichen hat oder 
nicht. Daher als kleinen Integer niemals char ohne explizites signed 
oder unsigned verwenden!

von g457 (Gast)


Lesenswert?

char hat bei Interger nix verloren, das ist ausschließlich für Zeichen. 
Für kleine Integer gibts signed char und unsigned char, und die benutzt 
man der besseren Les- und Portierbarkeit wegen vorzugsweise als int8_t 
und uint8_t. Und ja, char, signed char und unsigned char sind drei(!) 
verschiedene Datentypen.
Und ja, es ist nicht nur im Bereich µC üblich dass man den passenden 
Datentyp nimmt für das jeweilige Problem.

von Stefan F. (Gast)


Lesenswert?

In meinem ganzen Leben habe ich ausschließlich mit Computern gearbeitet, 
wo char technisch entweder mit int8_t oder mit uint8_t identisch war.

Aber: Die Hochsprachen wurde schließlich erfunden, um von Menschen 
gelesen werden zu können. Es geht nicht nur darum, die technische Größe 
des Speicherplatzes festzulegen, sondern auch für den Menschen 
darzustellen, wozu sie genutzt wird.

char = Zeichen
int = Zahlen

Alle mir bekannten Sprachen erlauben darüber hinaus die Definition 
eigener Aliase und Typen, was auch hauptsächlich dazu dient, den 
Quelltext für den Menschen besser lesbar zu machen.

So gibt es zum Beispiel size_t, um die Größe von Objekten im Speicher 
anzugeben, und FILE um ein File-Handle darzustellen.

von M.K. B. (mkbit)


Lesenswert?

Achim S. schrieb:
> Was meinst Du damit?

Ich bin wohl zu viel in C++ unterwegs. Das Problem tritt auf, wenn die 
Ausgabefunktion die Darstellung anhand des Datentyps bestimmt.
In printf gibt man selbst die Darstellung an, verwendet man aber cout in 
C++, dann wird die Ausgabe anhand des Typs ausgewählt. Da int8_t in der 
Regel einfach nur ein Alias für signed char ist (muss aber nicht so 
sein), sieht der Compiler char und stellt es als ASCII Zeichen und nicht 
als Zahl dar.

von Peter D. (peda)


Lesenswert?

Historisch sind Zeichen leider als signed char definiert worden, was 
einige Fallgruben bereitstellt.
Z.B. muß man bei der Konvertierung von Umlauten von ASCII nach 
LCD-Zeichensatz nach unsigned char casten, sonst gibt es Ärger, da 
Zeichencodes >127 nach signed int expandiert werden.
Das gleiche gilt für in Strings eingebettete Binärzahlen. Ohne den Cast 
kommt da Mumpitz raus, sobald das 7., 15. oder 23. Bit gesetzt ist.

von Fragenüberfragen (Gast)


Lesenswert?

g457 schrieb:
> Und ja, char, signed char und unsigned char sind drei(!) verschiedene
> Datentypen.

Nicht ganz. Es sind nur 2 Datentypen aber es ist 
implementierungsspezifisch wie man es so schön nennt ob char signed oder 
unsigned ist.

Ansonsten ist alles gesagt. Typen aus stdint.h verwenden. Von der Größe 
sollte man immer den Wertebereich nehmen, den man braucht und nicht auf 
optimierung achten.
Die oben erwähnten fast und least Typen gehören da auch dazu.

Char ist immer 8bit, spannender wird es bei int, das je nach Architektur 
von 16 bis 64 bit oder theoretisch auch mehr hat. Stdint.h stellt aber 
sicher, dass die Typen immer die angegebene Größe haben.

von Korrektur (Gast)


Lesenswert?

Stefanus F. schrieb:
> verarbeiten viele 16, 32 und 64 Bit Prozessoren solch kleine
> Integer Typen langsamer

Viele andere (> 8 Bit) stört es nicht. Also bitte nicht so pauschal!

von Dr. Sommer (Gast)


Lesenswert?

Fragenüberfragen schrieb:
> Nicht ganz. Es sind nur 2 Datentypen aber es ist
> implementierungsspezifisch wie man es so schön nennt ob char signed oder
> unsigned ist.

Nein, es sind wirklich drei. char verhält sich identisch zu entweder 
signed oder unsigned char, ist aber nicht der selbe Typ. Daher lässt 
sich ein char  auch weder zu signed char noch zu unsigned char* 
implizit konvertieren (ohne casten).
Ähnlich verhält es sich auf manchen Plattformen mit int und long - es 
können beide 32 Bit sein, sind aber nie der selbe Typ, und Pointer 
darauf sind nicht implizit konvertierbar.

von Dr. Sommer (Gast)


Lesenswert?

Danke Forum für die Formatierung. Es war gemeint:
signed char*
unsigned char*

von Rolf M. (rmagnus)


Lesenswert?

Korrektur schrieb:
> Stefanus F. schrieb:
>> verarbeiten viele 16, 32 und 64 Bit Prozessoren solch kleine
>> Integer Typen langsamer
>
> Viele andere (> 8 Bit) stört es nicht. Also bitte nicht so pauschal!

Inwiefern ist "viele" pauschal? Er hat ja nicht "alle" geschrieben. 
Zumindest mal für die überwiegende Anzahl der in freier Wildbahn 
auffindbaren Prozessoren (ARM und x86) gilt es.

Peter D. schrieb:
> Historisch sind Zeichen leider als signed char definiert worden, was
> einige Fallgruben bereitstellt.
> Z.B. muß man bei der Konvertierung von Umlauten von ASCII nach
> LCD-Zeichensatz nach unsigned char casten, sonst gibt es Ärger, da
> Zeichencodes >127 nach signed int expandiert werden.

Da bringst du ein paar Sachen durcheinander. Wenn du char nach unsigned 
char castest, gibt's kein Problem. Und ASCII kennt keine Umlaute.

> Das gleiche gilt für in Strings eingebettete Binärzahlen. Ohne den Cast
> kommt da Mumpitz raus, sobald das 7., 15. oder 23. Bit gesetzt ist.

Man muss einfach im Hinterkopf behalten, dass char nicht zum Rechnen zu 
verwenden ist.  Man speichert darin Text, aber sobald man rechnen muss, 
nimmt man signed char oder unsigned char, aber niemals nie nicht char. 
Und wenn es um ein 8-Bit-Register geht, wie bei dem LCD, dann eben 
uint8_t.
Wenn man das so macht, ist es einem auch völlig egal, ob char ein 
Vorzeichen hat oder nicht.

Fragenüberfragen schrieb:
> g457 schrieb:
>> Und ja, char, signed char und unsigned char sind drei(!) verschiedene
>> Datentypen.
>
> Nicht ganz. Es sind nur 2 Datentypen aber es ist
> implementierungsspezifisch wie man es so schön nennt ob char signed oder
> unsigned ist.

Das ist falsch. Aus ISO C (allerdings C99, da ich nichts neueres da 
hab):

"The three types char, signed char, and unsigned char are collectively 
called the character types. The implementation shall define char to have 
the same range, representation, and behavior as either signed char or 
unsigned char."

Char muss sich also gleich verhalten wie signed char oder unsigned char, 
aber es ist ein eigener Typ. In C spielt das keine so große Rolle, aber 
in C++ mit Templates und Überladung schon.

> Ansonsten ist alles gesagt. Typen aus stdint.h verwenden. Von der Größe
> sollte man immer den Wertebereich nehmen, den man braucht und nicht auf
> optimierung achten.

Naja, auf den Wertebereich zu beschränken, den man braucht, ist ja schon 
eine Optimierung. Man könnte auch immer den größtmöglichen Typ, also 
long long nehmen. Das hätte funktional ja keine besonderen Nachteile.

> Char ist immer 8bit, spannender wird es bei int, das je nach Architektur
> von 16 bis 64 bit oder theoretisch auch mehr hat.

Das gilt auch für char. Keiner der Standardtypen hat eine fixe Größe. 
Die meisten Programmierer werden selten bis nie damit zu tun haben, aber 
es gibt z.B. auch DSPs, die immer 24-bittig rechnen, wo char, short und 
int 24 Bit breit sind und long 48 Bit.

: Bearbeitet durch User
von Stefan F. (Gast)


Lesenswert?

>> verarbeiten viele 16, 32 und 64 Bit Prozessoren solch kleine
>> Integer Typen langsamer

> Viele andere (> 8 Bit) stört es nicht. Also bitte nicht so pauschal!

Ich kann zwischen "viele" und "alle" Unterscheiden. Kannst du es?

von Peter D. (peda)


Lesenswert?

Rolf M. schrieb:
> Wenn du char nach unsigned
> char castest, gibt's kein Problem.

Genau das habe ich doch geschrieben.

von Rolf M. (rmagnus)


Lesenswert?

Peter D. schrieb:
> Rolf M. schrieb:
>> Wenn du char nach unsigned
>> char castest, gibt's kein Problem.
>
> Genau das habe ich doch geschrieben.

Stimmt. Das hatte ich missverstanden.

von Karl (Gast)


Lesenswert?

Rolf M. schrieb:
> Man muss einfach im Hinterkopf behalten, dass char nicht zum Rechnen zu
> verwenden ist.  Man speichert darin Text, aber sobald man rechnen muss,
> nimmt man signed char oder unsigned char, aber niemals nie nicht char.
> Und wenn es um ein 8-Bit-Register geht, wie bei dem LCD, dann eben
> uint8_t.

Nun, manchmal muss man schon. Du bekommst eine Hex-Folge über Uart rein 
und möchtest die in Integer wandeln, oder umgekehrt. Klar, auf dem PC 
nimmst Du die entsprechende Funktion, aber auf dem uC erzeugt die zuviel 
Overhead. Da musst Du schonmal selbst Hand anlegen.

von W.S. (Gast)


Lesenswert?

Fragenüberfragen schrieb:
> Stdint.h stellt aber
> sicher, dass die Typen immer die angegebene Größe haben.

Aber eben nur dann, wenn eben diese Datei exakt zur verwendeten 
Zielplattform und zum verwendeten Compiler paßt.

Nun, das ist halt ein C-spezielles Problem. Wenn man ganz klassisch mit 
"unsigned char" oder "signed char" arbeitet, dann funktionert das auf 
allen Systemen (bis auf extreme Exoten, die es mittlerweile nur noch im 
Zoo gibt).

Man sollte sich wirklich mal einprägen, daß der ganze uint8_t Zirkus 
nichts weiter als einige Umdefinierungen in einer Headerdatei ist. Die 
C-Compiler arbeiten selbst nach wie vor mit den uralten Typen.



Prune schrieb:
> Mir geht es drum zu wissen ob es "üblich" in der uC Programmierung ist,
> dass man für kleine Zahlen den Datentyp Char statt Integer nimmt?

Alle derartigen Bedenken sind heutzutage eher altbacken bis obsolet. Mit 
den Cortexen ist die 32 Bit Welt in die Mikrocontroller eingezogen und 
sie hat fast alles andere plattgemacht. OK, bei Pollin kriegt man noch 
immer nen AT90xxx oder noch was älteres.

Aber mal im Ernst: für Zahlen - auch kleinere - nimmt man schlichtweg 
int oder auch long, weil die CPU ohnehin 32 bittig rechnet. Da hat es 
wirlich keinen Sinn, hie und da ein Byte im RAM sparen zu wollen, auf 
die Gefahr hin, daß man sich damit irgendwo selber ein Bein stellt.

Also: "üblich" ist sowas nicht, allenfalls bei Leuten, die es von früher 
her nicht lassen können.

Und nochwas: ein char ist eigentlich ein Textzeichen und sollte nicht 
als Integer zum Rechnen verstanden werden. In Pascal ist da ne saubere 
Grenze gezogen, in C leider nicht - weswegen in C eben immer wieder 
diese Probleme hochkochen.

W.S.

von 900ss (900ss)


Lesenswert?

W.S. schrieb:
> Aber eben nur dann, wenn eben diese Datei exakt zur verwendeten
> Zielplattform und zum verwendeten Compiler paßt.

Ziemlich dumm, wenn man die zum Compiler gelieferte Datei nicht 
verwendet. Wenn es keine gibt, dann halt selber machen.

W.S. schrieb:
> dann funktionert das auf allen Systemen (bis auf extreme Exoten, die es
> mittlerweile nur noch im Zoo gibt)

Wenn dein Horizont nicht weiter geht, dann bitte verallgemeinere das 
nicht ;)
Denk mal an DSPs.

W.S. schrieb:
> Alle derartigen Bedenken sind heutzutage eher altbacken bis obsolet. Mit
> den Cortexen ist die 32 Bit Welt in die Mikrocontroller eingezogen

Auch hier ist diese Aussage zwar richtig, aber es gibt halt auch viele 8 
Bit breite Controller. Und da ist diese Aussage ziemlicher Blödsinn, da 
rechnet sich der Controller tot an Bits, die nicht benötigt werden. Und 
ein Anfänger, der sich dieser Geschichte nicht sicher ist, wird mit 
einer Aussage dann leicht in die Irre geführt.

Besser finde ich:
Es hängt von der Architektur ab, auf 8 Bittern ist es sinnvoll 8 Bit 
breite Datentypen zu nutzen (die aus ISO C99 sind zu bevorzugen). Auf 32 
Bit breiten Controllern sind in der Regel die 32 Bit breiten Typen 
sinnvoller da der Controller eh mit 32 Bit arbeitet 
(Geschwindigkeitsvorteil).

von Yalu X. (yalu) (Moderator)


Lesenswert?

W.S. schrieb:
> Aber mal im Ernst: für Zahlen - auch kleinere - nimmt man schlichtweg
> int oder auch long, weil die CPU ohnehin 32 bittig rechnet. Da hat es
> wirlich keinen Sinn, hie und da ein Byte im RAM sparen zu wollen, auf
> die Gefahr hin, daß man sich damit irgendwo selber ein Bein stellt.

Es soll auch Anwendungen geben, die mehr als nur "hie und da" einzelne
Zahlen speichern. So werden bspw. Bilddaten selbst auf PCs mit vielen
GiB Hauptspeicher fast ausschließlich als 8-Bit-Werte pro Farbkanal
gespeichert. Warum? Weil 8 Bit fast immer ausreichend sind und weil das
enger Packen der Daten praktisch keine Nachteile mit sich bringt.
Spätestens, wenn man sich mit Videoschnitt u.ä. beschäftigt, lernt man
den um 75% reduzierten RAM-Verbrauch sehr zu schätzen.

900ss D. schrieb:
> Auf 32 Bit breiten Controllern sind in der Regel die 32 Bit breiten
> Typen sinnvoller da der Controller eh mit 32 Bit arbeitet
> (Geschwindigkeitsvorteil).

Man muss aber beachten, dass dieser Geschwindigkeitsvorteil ganz schnell
ins Negative kippen kann, wenn der Controller einen Cache besitzt und
man mehr als nur ein paar Hundert Zahlenwerte im Speicher halten möchte.
Der Geschwindigkeitsnachteil wird dann u.U. um ein Vielfaches größer als
der durch die pauschale Verwendung von 32-Bit-Variablen (theoretische)
Vorteil (alles schon erlebt :)).

von 900ss (900ss)


Lesenswert?

Yalu X. schrieb:
> Man muss aber beachten, dass dieser Geschwindigkeitsvorteil ganz schnell
> ins Negative kippen kann, wenn der Controller einen Cache besitzt und
> man mehr als nur ein paar Hundert Zahlenwerte im Speicher halten möchte

Hmmm.... ja, Spezialfälle gibt es immer. Da hilft es dann zu testen und 
messen. Aber in der Regel passt das schon wie ich es beschrieben habe.
Ja und sich die von mir oben angesprochen DSPs sind ja schon ein 
Spezialfall :)

von Rolf M. (rmagnus)


Lesenswert?

W.S. schrieb:
> Fragenüberfragen schrieb:
>> Stdint.h stellt aber
>> sicher, dass die Typen immer die angegebene Größe haben.
>
> Aber eben nur dann, wenn eben diese Datei exakt zur verwendeten
> Zielplattform und zum verwendeten Compiler paßt.

Sie gehört zum Compiler. Wenn da die Header-Datei für das falsche System 
dabei ist, ist was ziemlich kaputt. Dann wird der Rest aber auch nicht 
richtig tun, denn es wäre extrem unwahrscheinlich, dass nur dieser eine 
Header falsch ist und alle anderen Standard-Header korrekt.
Aber darüber hatten wir ja schon mehrfach diskutiert, und du scheinst 
das auch irgendeinem Grund immer noch nicht verstehen zu wollen.

900ss D. schrieb:
> Besser finde ich:
> Es hängt von der Architektur ab, auf 8 Bittern ist es sinnvoll 8 Bit
> breite Datentypen zu nutzen (die aus ISO C99 sind zu bevorzugen). Auf 32
> Bit breiten Controllern sind in der Regel die 32 Bit breiten Typen
> sinnvoller da der Controller eh mit 32 Bit arbeitet
> (Geschwindigkeitsvorteil).

Dazu kommt noch das Thema Speicherersparnis. Wenn ich ein sehr großes 
Array aus Werten habe, die alle nur z.B. bis 100 gehen, wäre es gerade 
auf einem µC ziemlih verschwenderisch, den Speicherverbrauch dafür um 
300% zu erhöhen, nur um keine 8-Bit-Datentypen verwenden zu müssen.

: Bearbeitet durch User
von 900ss (900ss)


Lesenswert?

Rolf M. schrieb:
> Sie gehört zum Compiler

Ja, so ist es. Hatte mich auch gewundert  weshalb W.S. das angemerkt hat 
(wenn die Datei passt). Entweder sie ist da oder nicht. Wenn Sie falsch 
ist, dann hat da jemand etwas durcheinander gewürfelt auf verschiedenen 
Toolchains.

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.