Forum: Mikrocontroller und Digitale Elektronik Datentyp mit 2bytes beim STM32


von Tim (Gast)


Lesenswert?

Hallo zusammen

Normalerweise (beim AVR) hat ja ein
1
int
 2bytes

Davon bin ich nun auch beim STM32 ausgegangen, und hab mir ein strukt 
angelegt.

Leider hat der int nun aber 4bytes.

Ich benötige diesen wertebereich jedoch nicht.
2bytes genügen.

Gibt es eine möglichkeit, einen Datentypen mit 2bytes zu definieren
oder ist bereits einer vorhanden?

Danke

von Linuxi (Gast)


Lesenswert?

Es gibt bestimmt sowas wie uint16_t oder so.

Int hat unterschiedliche größen je nach Zielsystem.

von Tim (Gast)


Lesenswert?

Linuxi schrieb:
> Es gibt bestimmt sowas wie uint16_t oder so.
>
> Int hat unterschiedliche größen je nach Zielsystem.

uint16_t kennt der compiler nicht :)

Ist ARM-GCC mit der CooCox IDE

von MZ (Gast)


Lesenswert?

binde mal folgende Headerdatei ein:

#include <stdint.h>

dort sind die uint8_t, uint16_t,... definiert

von Tim (Gast)


Angehängte Dateien:

Lesenswert?

MZ schrieb:
> binde mal folgende Headerdatei ein:
>
> #include <stdint.h>
>
> dort sind die uint8_t, uint16_t,... definiert

hab ich gerade gemacht.

Aber uint_16 ist nicht drinn (siehe bild)

von Tim (Gast)


Lesenswert?

oops :) doch

Fast und least
1
#if __STDINT_EXP(INT_MAX) >= 0x7fff
2
  typedef signed int int_fast16_t;
3
  typedef unsigned int uint_fast16_t;
4
#define __int_fast16_t_defined 1
5
#endif
6
7
8
#if !__int_least16_t_defined
9
typedef int32_t       int_least16_t;
10
typedef uint32_t    uint_least16_t;
11
#define __int_least16_t_defined 1
12
#endif
13
#endif

ich nehme an dass was ich möchte ist fast :)

von (prx) A. K. (prx)


Lesenswert?

Tim schrieb:
> Normalerweise (beim AVR) hat ja ein
1
int
 2bytes

"int" hat mindestens 2 Bytes. Kann auch mehr sein.

von (prx) A. K. (prx)


Lesenswert?

Tim schrieb:
> ich nehme an dass was ich möchte ist fast :)

Nicht, wenn du genau 2 Bytes willst. Denn beim STM32 ist int_fast16_t 
wieder 4 Bytes gross.

: Bearbeitet durch User
von Uli (Gast)


Lesenswert?

"short" ist immer 2 Byte.

von (prx) A. K. (prx)


Lesenswert?

Uli schrieb:
> "short" ist immer 2 Byte.

Falsch.

von Tim (Gast)


Lesenswert?

A. K. schrieb:
> Uli schrieb:
>> "short" ist immer 2 Byte.
>
> Falsch.

Ok also inzwischen, weiss ich was ich alles nicht nehmen kann.
Aber was ist denn nun 2bytes gross?

von B. S. (bestucki)


Lesenswert?

Uli schrieb:
> "short" ist immer 2 Byte.

Es gilt:
char <= short <= int <= long <= long long

Mit folgenden Einschränkungen:
- char ist der kleinste unterstützte Datentyp
- short und int sind mindestens 16 Bit breit
- long ist mindestens 32 Bit breit
- long long ist mindestens 64 Bit breit
- Die Grösse aller Datentypen sind ein Vielfaches der Grösse von char


Tim schrieb:
> Ok also inzwischen, weiss ich was ich alles nicht nehmen kann.
> Aber was ist denn nun 2bytes gross?

Ein uint16_t ist genau 2 Bytes gross. Das "Problem" an den Datentypen 
aus stdint.h ist, dass die (u)intXX_t laut Standard Typen nicht 
definiert werden müssen (und das ist auch gut so), die (u)int_fastXX_t 
und (u)int_leastXX_t Typen sehr wohl. Das sind die Beiden Typen, die 
auch verwendet werden sollten. Die (u)intXX_t werden normalerweise nur 
benötigt, wenn die exakte Breite aufgrund von Einschränkungen der 
Hardware zwingend nötig ist.

Die Frage ist also: Benötigst du wirklich genau 16 Bit, oder tun es auch 
mindestens 16 Bit?

von (prx) A. K. (prx)


Lesenswert?

[u]int16_t. Wenn diese Typ existieren, dann sind sie exakt 16 Bits 
breit.

von Uli (Gast)


Lesenswert?

Wer hat denn das mit dem short umdefiniert?
Dann hoffe ich mal der char immer noch nur ein Byte ist und long immer 
noch 4 Byte sind.

Das Int >= 2 Byte ist, sollte ja klar sein.

von (prx) A. K. (prx)


Lesenswert?

Uli schrieb:
> ... und long immer noch 4 Byte sind.

Falsch. Im 64-Bit Programmiermodell von Linux und diversen Unixen ist 
"long" 64 Bits breit.

> er hat denn das mit dem short umdefiniert?

Dennis Ritchie.

: Bearbeitet durch User
von Tim (Gast)


Lesenswert?

be stucki schrieb:
> Die Frage ist also: Benötigst du wirklich genau 16 Bit, oder tun es auch
> mindestens 16 Bit?

Ja,
da ich ein Strukt definiere und dieses strukt wird über einen 
definierten buffer gelegt.

Wenn nun also int variier im strukt, so habe ich die falschen daten...

von Fritz (Gast)


Lesenswert?

Uli schrieb:
> Wer hat denn das mit dem short umdefiniert?

Niemand, das war noch nie so definiert.

> Dann hoffe ich mal der char immer noch nur ein Byte ist

Ja.

Können aber mehr als 8 Bit sein...

> und long immer noch 4 Byte sind.

War auch noch nie so definiert.

> Das Int >= 2 Byte ist, sollte ja klar sein.

Das war dann wohl ein Glückstreffer.

von Rolf Magnus (Gast)


Lesenswert?

be stucki schrieb:
> Uli schrieb:
>> "short" ist immer 2 Byte.
>
> Es gilt:
> char <= short <= int <= long <= long long
>
> Mit folgenden Einschränkungen:

> - char ist der kleinste unterstützte Datentyp

und mindestens 8 Bit breit

> - short und int sind mindestens 16 Bit breit
> - long ist mindestens 32 Bit breit
> - long long ist mindestens 64 Bit breit
> - Die Grösse aller Datentypen sind ein Vielfaches der Grösse von char

be stucki schrieb:
> - Die Grösse aller Datentypen sind ein Vielfaches der Grösse von char
>
> Tim schrieb:
>> Ok also inzwischen, weiss ich was ich alles nicht nehmen kann.
>> Aber was ist denn nun 2bytes gross?
>
> Ein uint16_t ist genau 2 Bytes gross.

Er kann auch 1 Byte groß sein. Ist er auf dieser Plattform aber nicht.

> Die Frage ist also: Benötigst du wirklich genau 16 Bit, oder tun es auch
> mindestens 16 Bit?

Und danach kommt dann die Frage: Soll der Typ möglichst klein oder 
möglichst schnell sein? Danach entscheidet man, ob least oder fast.

von B. S. (bestucki)


Lesenswert?

Rolf Magnus schrieb:
> Er kann auch 1 Byte groß sein. Ist er auf dieser Plattform aber nicht.

Stimmt. Denn in C ist ein Byte gleich gross wie ein char.


Tim schrieb:
> da ich ein Strukt definiere und dieses strukt wird über einen
> definierten buffer gelegt.

Ich nehme mal an, dass du der selbe Tim bist, wie in folgendem Beitrag:
Beitrag "Strukt hat unterschiedliche länge"

Daher gibts von mir wieder die gleiche Antwort:
be stucki schrieb:
> Tim schrieb:
>> bmp_f_hdr = (struct bmp_file_header *)&ucBuffer[0];
>
> Ganz ganz unschön, fehleranfällig und nicht portabel.
> Stichwort: Padding Bytes
>
> Schreib eine Funktion, der du einen Header übergeben kannst und dir eine
> korrekt befüllte Struktur zurückliefert.

von Tim (Gast)


Lesenswert?

Es soll ja nicht portabel sein.
Und wenn es es sauber programmiert ist, auch nicht fehleranfällig

von Uli (Gast)


Lesenswert?

Dann sind halt alle Compiler die mir untergekommen sind Glückstreffer.
Ich hatte noch nie einen in den letzten 30 Jahren der das anders gemacht 
hat.
Aber man lernt halt nie aus.

von B. S. (bestucki)


Lesenswert?

Tim schrieb:
> Es soll ja nicht portabel sein.
> Und wenn es es sauber programmiert ist, auch nicht fehleranfällig

Na gut. Wundere dich aber bitte nicht, wenn es mit der nächsten 
Compilerversion nicht mehr funktioniert.

Die Grösse eines Datentyps kannst du mit dem sizeof Operator ermitteln. 
Dieser Operator liefert dir die Grösse des Types in Bytes, wobei ein 
Byte der Grösse eines chars entspricht.
Alternativ kannst du auch im Handbuch deines Compilers nachlesen, wie 
gross die Datentypen sind.

von (prx) A. K. (prx)


Lesenswert?

Uli schrieb:
> Ich hatte noch nie einen in den letzten 30 Jahren der das anders gemacht
> hat.

Ich schon. Implementier mal 16-Bit Typen auf einer Maschine, die das 
nicht mitbringt. Kann man machen, wäre bei der Maschine aber bös 
umständlich und langsam gewesen, also liess ich es sein. short=int, und 
in der 32-Bit Version waren das eben 32 Bits.

von W.S. (Gast)


Lesenswert?

MZ schrieb:
> dort sind die uint8_t, uint16_t,... definiert

.. und dort kann man auch genau sehen, woraus diese Typen definiert 
sind. Genau DAS kann man dann für diesen Compiler auch direkt benutzen.

Ich tippe mal auf unsigned short für einen 16 Bit integer. Im Grunde 
kennt kein C-Compiler von sich aus sowas wie uintBLA_t. Das ergibt sich 
immer nur aus irgendeiner stdint.h die man sich bei Bedarf und Laune 
auch selber schreiben kann und in der all diese monströsen 
Typbezeichnungen auf die altbekannten Typen char und int nebst 
Qualifiern wie long und short zurückgeführt sind.

Aber das nächste Problem ist die Packungsdichte: Bei Structs sorgt der 
Compiler dafür, daß der nächste Member auf einer passenden Adresse 
landet. Manche CPU's können auf 16 und 32 Bit Daten nämlich nur auf 
"geraden" Adressen zugreifen. Deshalb kann es je nach Zielarchitektur 
dazu kommen, daß du zwar nen 16 Bit Integer hinbekommst, aber der 
Compiler direkt danach 2 Füll-Bytes einfügt. Das Gleich gilt für Char's.

W.S.

von Tim (Gast)


Lesenswert?

W.S. schrieb:
> Ich tippe mal auf unsigned short für einen 16 Bit integer

Vielen Dank!

Es war ein short!


Nun klappts auch mit dem Strukt :)


Noch zur Info!
ARM-GCC bzw. der STM32 kann byteweise auf den Speicher hinter dem Strukt 
zugreifen.

Habs getestet in dem ich ein strukt mit zwei chars (welche übrigens 8bit 
sind) angelegt habe und dann im speicher nachgesehen habe, ob diese 
direkt aufeinander folgen.

Es war so!

Nun mache ich einfach zu beginn meines Programms im main eine prüfung 
mit sizeof() allen datentypen ob diese meinen benötigten längen 
entsprechen.

Sollte also in zukunf der compiler oder sonstwas ändern, ist das problem 
zwar nicht automatisch gelöst, aber ich kriege es zumindest gleich mit!

Danke

von TriHexagon (Gast)


Lesenswert?

Und warum machst du es nicht wie jeder andere und nimmst die 
Definitionen aus stdint.h? Warum so umständlich? Die wurden nicht zum 
Spaß in C99 eingeführt.

von Tim (Gast)


Lesenswert?

TriHexagon schrieb:
> Und warum machst du es nicht wie jeder andere und nimmst die
> Definitionen aus stdint.h? Warum so umständlich? Die wurden nicht zum
> Spaß in C99 eingeführt.

weil wir ja gehört haben, dass uint_16_t alles von 2bytes aufwärts sein 
kann.

Was nützt mir das, wenn ich uint_16_t nehme und es dann 4 bytes sind?
Dann geht mein strukt ja trozdem nicht über meinen buffer.

Angenommen ich habe im strukt 4 mal nen uint16.
Wenn ich davon ausgehe, dass uint16 2 bytes sind dann lege ich einen 
solchen buffer an:

unsigned char buffer[8];

wenn es nun 4bytes sind, reicht es aber nicht!


Also erklär mir bitte, inwiefern mir die stdint.h etwas nützt?

von TriHexagon (Gast)


Lesenswert?

Wenn uint16_t größer als 2 Byte ist, kannst du es auch nicht mit short 
hinbiegen.

Tim schrieb:
> unsigned char buffer[8];
>
> wenn es nun 4bytes sind, reicht es aber nicht!

Dann machst du einfach:
1
uint8_t buffer[sizeof(struct x)];

Diese Definitionen aus stdint.h sind zudem verständlicher als die 
dämlich unpräziesen short, int, long Bezeichnungen. In jedem Forum kommt 
es zu einer neuen Streiterei wie diese sind, wie z.B. hier.

von Guest (Gast)


Lesenswert?

Tim schrieb:

> weil wir ja gehört haben, dass uint_16_t alles von 2bytes aufwärts sein
> kann.

Nö. uint_16_t hat IMMER 2 byte. deshalb ja die stdint.h.

> Was nützt mir das, wenn ich uint_16_t nehme und es dann 4 bytes sind?
> Dann geht mein strukt ja trozdem nicht über meinen buffer.

Das hat was mit dem alignment der struct zu tun.

>
> Angenommen ich habe im strukt 4 mal nen uint16.
> Wenn ich davon ausgehe, dass uint16 2 bytes sind dann lege ich einen
> solchen buffer an:
>
> unsigned char buffer[8];
>
> wenn es nun 4bytes sind, reicht es aber nicht!
>
> Also erklär mir bitte, inwiefern mir die stdint.h etwas nützt?

stdint.h liefert dir Variablen von denen Du genau weist wie groß sie 
sind. Das alignment in den Structs kann man je nach compiler mit 
#pragmas oder _attribute_ ((aligned (8)) beeinflussen. Deinen Buffer 
solltest Du eh mit anderst definieren.

z.B. Für einen Buffer in welchen mystruct_t 4 mal rein passt

mystruct_t buffer[4];

oder

mystruct_t * buffer;
buffer = malloc(sizeof(mystruct_t)*4)

von (prx) A. K. (prx)


Lesenswert?

Tim schrieb:
> weil wir ja gehört haben, dass uint_16_t alles von 2bytes aufwärts sein
> kann.

Wiederholter Unsinn bleibt Unsinn.

von Dr. Sommer (Gast)


Lesenswert?

W.S. schrieb:
> .. und dort kann man auch genau sehen, woraus diese Typen definiert
> sind. Genau DAS kann man dann für diesen Compiler auch direkt benutzen.
Aber wozu? Warum nicht den standardisierten uint16_t Typ verwenden? Dann 
weiß auch jeder, der den Code liest, was man eigentlich bezweckt! Die 
"16" ist da nicht zum Spaß, die besagt "Sechzehn bits", und genau die 
will der OP doch haben?!

Tim schrieb:
> Habs getestet in dem ich ein strukt mit zwei chars
Alle Cortex-M3,4 können das, und damit auch die STM32F1,2,3,4. Aber 
nicht die STM32F0 (Cortex-M0). Dokumentiert ist das im jeweiligen 
"ARMv*M Architecture Reference Manual" (* = 6 für Cortex-M0, * = 7 für 
Cortex-M3, 4), suche dort nach "alignment".

Tim schrieb:
> weil wir ja gehört haben, dass uint_16_t alles von 2bytes aufwärts sein
> kann.
Nein. Nur uint_fast16_t und uint_least16_t. uint16_t ist immer genau 16 
Bits, und damit genau das was du willst. Der Leser weiß auch sofort, 
dass du genau 16bit willst.
Siehe:
http://en.cppreference.com/w/c/types/integer

TriHexagon schrieb:
> Wenn uint16_t größer als 2 Byte ist
... was nie der Fall ist - du meinst wohl "wäre".

Tim schrieb:
> Nun mache ich einfach zu beginn meines Programms im main eine prüfung
> mit sizeof() allen datentypen ob diese meinen benötigten längen
> entsprechen.
Indem du das Programm als C++ statt C kompilieren lässt, kannst du 
solche Überprüfungen auch schon dann machen wenn der Compiler läuft, und 
nicht erst während das Programm ausgeführt wird:
1
static_assert(sizeof(uint16_t)*CHAR_BIT == 16, "uint16_t ist nicht 16 bit gross");
Wobei, wie gesagt, dieser Fall nie eintreten wird, da uint16_t immer 
16bit groß ist.

von Tobi D. (fanti)


Lesenswert?

In Coocox schreibe ich die Variablen immer so (wenn der Code nicht 
portabel sein soll!):
u8
u16

von Dr. Sommer (Gast)


Lesenswert?

Tobi D. schrieb:
> In Coocox schreibe ich die Variablen immer so (wenn der Code nicht
> portabel sein soll!):
> u8
> u16
Du schreibst absichtlich unportablen Code? Ist ja schön wenn du das 
machst, aber das hier ratschlagartig zu verbreiten ist kontraproduktiv. 
Ich verstehe nicht, was so schwierig an "uint16_t" ist.

von Tim (Gast)


Lesenswert?

Dr. Sommer schrieb:
> Tobi D. schrieb:
>> In Coocox schreibe ich die Variablen immer so (wenn der Code nicht
>> portabel sein soll!):
>> u8
>> u16
> Du schreibst absichtlich unportablen Code? Ist ja schön wenn du das
> machst, aber das hier ratschlagartig zu verbreiten ist kontraproduktiv.
> Ich verstehe nicht, was so schwierig an "uint16_t" ist.

Gut!

Nun hab ichs verstanden :)

Hab nun uint16_t und uint8_t verwendet.

Läuft TipTop!

von Ingo (Gast)


Lesenswert?

Es gibt Leute, die Sparen Zeichen ohne Ende. Ich kenne jemanden, der 
benutzt für Variablennamen nur einen Buchstaben. Dementsprechend schlimm 
und schwer ist der Code lesbar

von Rolf Magnus (Gast)


Lesenswert?

Tim schrieb:
> Noch zur Info!
> ARM-GCC bzw. der STM32 kann byteweise auf den Speicher hinter dem Strukt
> zugreifen.

Das hängt vom Prozessor ab. Ich hab auch schon einen ARM programmiert, 
der beim Versuch, mit falschem Alignment zuzugreifen, eine 
Hardware-Exception ausgelöst hat.

> Habs getestet in dem ich ein strukt mit zwei chars (welche übrigens 8bit
> sind) angelegt habe und dann im speicher nachgesehen habe, ob diese
> direkt aufeinander folgen.
>
> Es war so!

Das ist aber wenig überraschend. Du hast dir da genau den einen Fall 
rausgesucht, wo's praktisch nie Alignment-Probleme gibt, denn char hat 
normalerweise keine Alignment-Anforderungen. Dementsprechend braucht 
eine struct, die ausschließlich aus chars besteht, auch keinerlei 
Padding-Bytes. Spannend wird es eher, wenn eben gerade nicht alle 
Elemente vom Typ char sind.

> Nun mache ich einfach zu beginn meines Programms im main eine prüfung
> mit sizeof() allen datentypen ob diese meinen benötigten längen
> entsprechen.

Das ist zwar irgendwie umständlich, aber geht natürlich auch.

Tim schrieb:
> TriHexagon schrieb:
>> Und warum machst du es nicht wie jeder andere und nimmst die
>> Definitionen aus stdint.h? Warum so umständlich? Die wurden nicht zum
>> Spaß in C99 eingeführt.
>
> weil wir ja gehört haben, dass uint_16_t alles von 2bytes aufwärts sein
> kann.

Da hast du es genau falsch rum. short kann alles ab 16 Bit sein, 
uint16_t dagegen hat exakt 16 Bit. uint16_t könnte aber auch 1 Byte groß 
sein, wenn CHAR_BIT == 16. Dann hat man das gleiche Problem aber auch 
mit allen anderen Typen.

> Angenommen ich habe im strukt 4 mal nen uint16.
> Wenn ich davon ausgehe, dass uint16 2 bytes sind dann lege ich einen
> solchen buffer an:
>
> unsigned char buffer[8];
>
> wenn es nun 4bytes sind, reicht es aber nicht!

Wenn du einen Puffer willst, der genau die richtige Grröße für deine 
Struct hat, mach halt:
1
unsigned char buffer[sizeof(deine_struct)];

von Tim (Gast)


Lesenswert?

Rolf Magnus schrieb:
> unsigned char buffer[sizeof(deine_struct)];

Genial! :) Das ich da nicht drauf gekommen bin :)

Aber ich denke es ist dennoch sinnvoll, sich gedanken über die Grösse 
der einzelnen elemente des strukts zu machen.

Ansonsten wird ja Speicherplatz verschwendet...

von (prx) A. K. (prx)


Lesenswert?

Rolf Magnus schrieb:
> Wenn du einen Puffer willst, der genau die richtige Grröße für deine
> Struct hat, mach halt:
>
1
> unsigned char buffer[sizeof(deine_struct)];
2
>

Man sollte dann nur auf die Versuchung verzichten darauf per Cast und 
Struct zuzugreifen. Alignment ist nicht gewährleistet.

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.