Forum: Compiler & IDEs Datentypen wie "uint8_t"


von Roland (Gast)


Lesenswert?

Hallo!

Also ich bin gerade dabei, mir langsam aber sicher C-Kenntnisse im
Selbststudium beizubringen..

Möchte auch einige kleine Programme für einen AVR Controller
schreiben.

Nur komme ich als Anfänger einfach nicht klar mit all den Datentypen
und deren bezeichnung im WinAVR.

Wie z.B.: uint8_t

Habe die include Datei durchforstet, welche mir am Ehesten Infos
liefern könnte und zwar die "inttypes.h".  Darin fand ich z.B.: das:


 \code
    #include <inttypes.h>

    uint8_t smallval;
    int32_t longval;
    ...
    printf("The hexadecimal value of smallval is " PRIx8
           ", the decimal value of longval is " PRId32 ".\n",
     smallval, longval);
    \endcode

, was mir jedoch nicht wirklich weiter hilft.

Wenn ich z.B.: ein paar Bytes in ein array speichern möchte, wobei ja
jedes Byte ein Zeichen repräsentiert, welchen Datentyp nehme ich dazu?

Nehmen wir an, ich will das Wort "TEST" irgendwo hin schicken (egal,
ob per UART oder an irgendeinen Speicher, ....)

Erstelle ich dann ein Array so?

uint8_t array[3];
array[0] = "T";
array[1] = "E";
array[2] = "S";
array[3] = "T";

oder vielleicht so :

unsigned char array[3];
array[0] = "T";
array[1] = "E";
array[2] = "S";
array[3] = "T";


Also die Frage ist, ist das egal, in welchem Datentyp ich so etwas
speichere?
Wenn ich "unsigned char" wähle, speicher ich tatsächlich den
Buchstaben "T", richtig?

Und wenn ich int wähle, wird wohl der Wert von "T" als dezimales
"84" gespeichert, was binär wohl "10000100" bedeutet.

Doch zurück zum eigentlichen Thema: Was bedeutet nun "uint8_t"?

Einen int mit 8Bit Größe?

Ach und gibt es irgendwo eine komplette Übersicht über die datentypen,
die man häufig bei der AVR Programmierung mit dem avr-GCC
verwendet/benötigt?



Danke!

Mit freundlichem Gruß... Roland

von Detlev Tietjen (Gast)


Lesenswert?

Schau doch hier mal nach:

http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Standardisierte_Integer.28Ganzzahl.29-Typen

Ansonsten erlaubt C übrigens auch das:

char text[] = "Test";

text ist dann 5 Bytes groß, da das Stringendezeichen \0 angehängt wird
(Wie es sich gehört).

Und: Wenn du ein array mit nur 3 Elementen definierst, darfst du nicht
auf das vierte (array[3]) zugreifen! Das gibt in der Regel keine
Fehlermeldung, du zerstörst aber ungewollt andere Daten. Es ist eher
unwahrscheinlich, dass dein Programm dann das tut, was du willst.

Gruß, Detlev

von DIrk (Gast)


Lesenswert?

UINT8_t == unsigned char
U -> unsigned   ohne Vorzeichen
INT -> Integer
8 -> Bit länge
_t -> Kennung das ein Typ ist


INT32 == signed long

In der Datei "inttypes.h" sollte die Zuordnung drin stehen
(typedef).

Texte werden meist als signed verarbeitet. In deinem Fall geht es aber
auch so.
Variablen wie "int" sollte man nicht verwenden da sie vom Prozessor
abhänig sind (16-64bit länge).

von Karl heinz B. (kbucheg)


Lesenswert?

> Wenn ich "unsigned char" wähle, speicher ich tatsächlich den
> Buchstaben "T", richtig?
>
> Und wenn ich int wähle, wird wohl der Wert von "T" als dezimales
> "84" gespeichert, was binär wohl "10000100" bedeutet.

Überraschung:
in beiden Fällen wird der Zahlenwert 84 abgelegt.
In einem Computer ist alles einfach nur eine Zahl. Es
ist nur so, dass der Datentyp 'char' bei Ein/Ausgabe
anders behandelt wird. Wird ein char ausgegeben, dann
sorgt die Ausgabefunktion dafür, dass die 84 am Display
für das aufleuchten der Pixel sorgen, die ein 'T' ergeben.
Wird ein int ausgegeben, dann werden 2 Zeichen ausgegeben.
Das Zeichen '8' gefolgt vom Zeichen '4'. Dein Gehirn
macht daraus wieder 84.


> Doch zurück zum eigentlichen Thema: Was bedeutet nun "uint8_t"?
> Einen int mit 8Bit Größe?

Yep.

  u               unsigned (also nur positive Zahlen, keine negativen)
  uint            unsigned int  (also nur ganze Zahlen)
  uint8           mit 8 Bit (also: 0 bis 255)
  uint8_t         das _t steht für: das ist ein Datentyp, um
                  Verwechslungen mit Variablennamen zu vermeiden.


> unsigned char array[3];
> array[0] = "T";
> array[1] = "E";
> array[2] = "S";
> array[3] = "T";

So ganz sicher nicht. Zaehl mal die Zuweisungen. Das sind 4
und nicht 3! In der Deklaration eines Arrays wird aber die
Anzahl der benötigten Elemente angegeben und nicht der höchste
zu erwartende Index. Wenn schon dann

unsigned char array[4];

(Du solltest auch noch mal über den Unterschied von " und ' nach-
denken. " benutzt man für einen kompletten String, ' benutzt
man für ein einzelnes Zeichen).

Aber das macht man eigentlich auch nicht. Denn mit so einem
Array (das ja als string herhalten muss), kann man eher wenig
anfangen (zumindest ist es lästig). In C gibt es die Konvention,
dass ein String immer mit einem '\0' Zeichen aufhört. Alle
Funktionen die mit Strings arbeiten, wissen das, zb auch die
UART-String-Ausgabe Funktion. d.h. der String "TEST" besteht
eigentlich aus 5 (!) Zeichen und nicht 4, da ja der abschliessende
'\0' auch irgendwo gespeichert werden muss.

unsigned char array[5];

array[0] = 'T';
array[1] = 'E';
array[2] = 'S';
array[3] = 'T';
array[4] = '\0';

Das ist aber noch mächtig umständlich.
Viel einfacher ist:

unsigned char array[5] = "TEST";

(geht aber nur bei Strings. Der Compiler sorgt dafür, dass
im Prinzip genau die obigen 5 Zuweisungen gemacht werden.

Das einzige, was jetzt noch lästig ist, ist dass ich den
String "TEST" abzählen muss um zu wissen, wie gross das
Array sein muss.

unsigned char array[] = "TEST";

Jetzt übernimmt der Compiler das abzaehlen. Das hat den Vorteil,
wenn sich der String "TEST" ändert, zb. auf "NOCH EIN TEST", dann
muss nicht ich die Array-Größe abzählen, sondern das erledigt
der Compiler für mich.

> Also ich bin gerade dabei, mir langsam aber sicher C-Kenntnisse im
> Selbststudium beizubringen..

Ich hoffe, du hast Literatur dafür. Online-Seiten und Web-Tutorials
sind kein Ersatz für ein vernünftiges Buch.

von Roland (Gast)


Lesenswert?

Danke für all die Antworten! Ist echt ein super Forum hier!!

Ja, ich bin dabei, mir ein Buch über ANSI - C zuzulegen.

Also ich hab das ganze nun einigermaßen durchblickt , bis auf:

1.)
unsigned char  bezeichnet ja wohl ein Zeichen

Ein Zeichen kann aber nicht "negativ" sein, oder?

Aber wozu gibt es dann "signed char"?

2.) zu Dirks Aussage:

"
Variablen wie "int" sollte man nicht verwenden da sie vom Prozessor
abhänig sind (16-64bit länge).
"

Ein Integer Wert aht also MINDESTENS 16 Bit?
Hat uint8_t denn nicht nur 8 Bit?

Ich meine, klar,  ein unsigned int geht von "0" bis "65536", also
muss er 16 Bit "breit" sein..

Dann ist allerdings diese Aussage (scheinbar) wieder Mist:

"uint8           mit 8 Bit (also: 0 bis 255)"




Grüße... Roland

von Karl heinz B. (kbucheg)


Lesenswert?

> Aber wozu gibt es dann "signed char"?

Das 'Problem' ist:
In Deiner Vorstellung ist 'char' unweigerlich mit 'Zeichen'
assoziert. Nun, ja. So falsch ist das auch wieder nicht, wenn
man den Gedanken nicht zu ernst nimmt. In Wirklichkeit wäre
für 'char' eine ganz andere Beschreibung angebracht:
Ein 'char' nimmt kleine Zahlen auf, und wird bei Ein-/Ausgabe
anders behandelt als die Datentypen für Zahlen. Aber: Ein
'char' ist auch nur ein Datentyp in dem Zahlen, eben kleine
Zahlen, gespeichert sind. Man kann mit einem 'char' genauso
rechnen wie mit einem int, long oder double.

zu 2.
Das Problem ist, dass nichts und niemand einem Compiler exakt
vorschreibt, wieviele Bits ein char, int oder long den haben
muss. In C ist das alles der Implementierung überlassen. Es
existieren lediglich ein paar grundlegende Regeln. zb. das
ein int mindestens soviele Bits haben muss wie ein char. Oder
das ein long mindestens soviele Bits haben muss wie ein int.
Noch nicht mal die Bitbreite eines char (normalerweise 8)
ist festgelegt. Theoretisch kann ein char auch aus 9 oder
11 Bits bestehen.

> Dann ist allerdings diese Aussage (scheinbar) wieder Mist:
> "uint8           mit 8 Bit (also: 0 bis 255)"

Wieso soll das Mist sein.
Mit 8 Bit kann man bis 255 zählen.

uint8  ist auf den meisten Maschinen ein Synonym für unsigned char.

erst ein uint16 ist das was auf den meisten Maschinen ein
unsigned int ist.

Im Ur-C gab es nur die Datentypen
char, int, long, float, double
Wie gesagt: Für diese Datentypen gibt es zwar ein paar Regeln
aber nichts verbindliches darüber, wieviele Bits da jeweils
drinn sind. Das ist bei der normalen Programmierung tatsächlich
eher irrelevant, wird aber bei der Programmierung von µC so
richtig interessant. Da es aber im Ur-C dafür nichts Vernünftiges
gab, hat man dann später zusätzliche Bezeichner eingeführt, aus
deren Namen auch hervorgeht, über wieviele Bits der Datentyp
eigentlich besteht. Damit hat man den Programmierer auch
davon entbunden darüber nachzudenken, welchen Datentyp er
tatsächlich braucht, wenn er einen unsigned mit 16 Bits haben
will. Er schreibt einfach uint16_t, und gut ists. Das ein
uint16_t auf manchen Maschinen einem 'unsigner long' entspricht,
auf anderen wieder einem 'unsigned int', während es auf einer
3. Maschine ev. ein 'unsigned short int' ist, braucht in nicht
mehr zu kümmern.

von Karl heinz B. (kbucheg)


Lesenswert?

Wichtig ist noch:
Ein uint8_t oder uint16_t oder wie sie alle heissen, sind
keine eigenen Datentypen. Das sind lediglich typedef's
für die Grunddatentypen.
Im Grunde hätte man die auch 'SchnurDiBur' oder 'ASDF'
nennen können. Nur ist es halt naheliegender, das Zeugs
uint8_t oder uint16_t zu nennen.

von Roland (Gast)


Lesenswert?

Ok, nun hab ichs verstanden!

DANKE! ;-)

von Roland (Gast)


Lesenswert?

Es wär doch irgendwie nett, wenn Programmer´s Notepad diese
"typedef-Datentypen" trotzdem hervorheben bzw. blau schreiben
würde..

Kann man das irgendwie veranlassen?

Sonst wirds schnell mal unübersichtlich, wenn eine Funktion mehrere
Parameter übergibt...

Grüße...

von Roland (Gast)


Lesenswert?

Oh, tschuldigung, habs bereits gefunden unter

Style--> Schemes-->Keywords    ;-)

Sry...

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


Lesenswert?

Bemerkung zu "char": ja, es soll ein Zeichen aufnehmen können.
Anders als bei "int" (das immer ein Alias für "signed int" ist)
ist aber bei char die Vorzeichenhaftigkeit/-losigkeit nicht im
Standard vorgeschrieben, sodass eine Implementierung den Typ
"char" wahlweise wie "signed char" oder wie "unsigned char"
implementieren darf.  Damit soll sie in die Lage versetzt werden,
den Datentyp so zu wählen, wie es ihr auf Grund anderer
Randbedingungen (Rechengeschwindigkeit, historische Nutzung
von nicht-C-Implementierungen auf gleichem System) am besten
gefällt.

Die Randbedingung für die Größen von Datentypen sind übrigens
(mal davon ausgehend, dass wir nur Maschinen mit Zweierkomplement-
Darstellung für Integers betrachten):

. char >= 8 bits
. int >= 16 bits
. short >= 16 bits
. long >= 32 bits
. long long >= 64 bits

Sieht auf den ersten Blick einleuchtend aus, hat aber auch ein
paar Pferdefüße, die man nicht auf den ersten Blick sieht.
Insbesondere ist es halt durch den Standard nicht garantiert,
dass es überhaupt einen Datentyp mit 8 Bit Breite geben muss.
Gerüchtehalber soll es zumindest einige DSPs geben, die gar
keine 8-bit-Zahlen verarbeiten können, bei denen ist dann
sizeof(char) == sizeof(short) == sizeof(int) = 32.

Der Vorteil der Benutzung der exact width integer types (wie
uint8_t) ist es in diesem Falle, dass das Programm nicht
wundersame Dinge zur Laufzeit macht, weil der Programmierer
annahm, dass sein "unsigned char" von 255 auf 0 überrollt,
sondern dass das Programm sich bereits mit einem compile time
error verabschiedet, weil eine solche Maschine eben keinen
uint8_t kennt.

von Ange (Gast)


Lesenswert?

Hallo Zusammen,

ich habe ebenfalls den Datentyp uint8_t. Ist folgende Zuweisung richtig:

uint8_t var=1;

Nun möchte ich mir gerne den Inhalt über printf() ausgeben lassen. Wenn 
ich schreibe printf("variablenwert %d", &var); erscheint eine Warnung 
auf Grund des Datentyps. Was nehme ich denn anstelle von d um mir den 
Wert von var ausgeben zu lassen?


Gruß Ange

von Stefan E. (sternst)


Lesenswert?

1
printf("variablenwert %d", var);

Und bitte mache zukünftig für deine Fragen einen neuen Thread auf, und 
hänge dich nicht an einen anderen uralten Thread ran, schon gar nicht, 
wenn deine Frage praktisch nichts mit diesem alten Thread zu tun hat.

von Karl H. (kbuchegg)


Lesenswert?

Stefan Ernst schrieb:

> wenn deine Frage praktisch nichts mit diesem alten Thread zu tun hat.

Selbst dann:
Wenn ein Thread einmal älter als, sagen wir mal, 6 Monate ist, macht es 
in den wenigsten Fällen Sinn den Thread wieder hervorzukramen. Einzige 
Ausnahme: wenn man sich gezielt auf ein Vorgängerposting in diesem 
Thread bezieht, weil man dazu noch etwas zu sagen hat (Ergänzungen, neue 
Entwicklungen, etc.)

von Klaus W. (mfgkw)


Lesenswert?

Ange schrieb:
> Hallo Zusammen,
>
> ich habe ebenfalls den Datentyp uint8_t. Ist folgende Zuweisung richtig:
>
> uint8_t var=1;

Ja, richtig.


>
> Nun möchte ich mir gerne den Inhalt über printf() ausgeben lassen. Wenn
> ich schreibe printf("variablenwert %d", &var); erscheint eine Warnung
> auf Grund des Datentyps. Was nehme ich denn anstelle von d um mir den
> Wert von var ausgeben zu lassen?
>
>
> Gruß Ange

Legale Versionen wären:
1
#include <stdint.h>
2
#include <inttypes.h>
3
4
5
int main( int nargs, char **args )
6
{
7
  uint8_t     var = 1;
8
  printf( "var ist %d\n", (int)var );          // mäßig empfehlenswert
9
  printf( "var ist %u\n", (unsigned int)var ); // schon besser
10
  printf( "var ist %"PRIu8"\n", var );         // perfekt, benötigt inttypes.h
11
12
  return 0;
13
}

von Peter (Gast)


Lesenswert?

Jörg Wunsch schrieb:
> . char >= 8 bits
> . int >= 16 bits
> . short >= 16 bits
> . long >= 32 bits
> . long long >= 64 bits

Dazu bleibt anzumerken, dass das mit hoher Wahrscheinlichkeit so ist und 
eine gute Annahme für die reale Welt ist, es aber nicht so verbindlich 
standardisiert ist.

sizeof(char) == 1 und sizeof(char) <= sizeof(short) <= sizeof(int) <= 
sizeof(long) <= sizeof(long long) ist dort die einzige Wahrheit.
Beachte die "=".

Gruß – Peter

von Stefan E. (sternst)


Lesenswert?

Peter schrieb:
> Dazu bleibt anzumerken, dass das mit hoher Wahrscheinlichkeit so ist und
> eine gute Annahme für die reale Welt ist, es aber nicht so verbindlich
> standardisiert ist.

Doch, ist es.
Siehe dazu z.B. C99-Standard 5.2.4.2.1

Peter schrieb:
> sizeof(char) == 1 und sizeof(char) <= sizeof(short) <= sizeof(int) <=
> sizeof(long) <= sizeof(long long) ist dort die einzige Wahrheit.
> Beachte die "=".

Und? Die "=" eröffnen lediglich die Option, dass auch alle Typen die 
gleiche Größe haben könnten.

von Lutz (Gast)


Lesenswert?

Roland schrieb:
> Ich meine, klar,  ein unsigned int geht von "0" bis "65536", also
> muss er 16 Bit "breit" sein..

Leichen fleddern macht ja soooo viel Spaß. Fledder ich doch mit: Es geht 
von 0 bis 65.535, was 65.536 verschiedene Werte ergibt.

Beitrag #5847292 wurde von einem Moderator gelöscht.
Beitrag #5847373 wurde von einem Moderator gelöscht.
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.