mikrocontroller.net

Forum: Compiler & IDEs 8 bit, 16 bit mischung in struktur - 8 bit breiten speicher vorgaukeln


Autor: Thomas (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
folgende Problematik.
Vorhanden ist eine gegebene Struktur mit unterschiedlichen datentypen 
(uint8 / uint16). Der vorhandene Arbeitsspeicher ist 16-bit breit -> 
folge, compiler versucht natürlich, uint16-variablen in einer zelle zu 
speichern, wobei bei der mischung von uint8 und uint16 datentypen somit 
lücken (unbenutzt) entstehen.
ziel ist nun, die struktur mittels uart-schnittstelle (8-bit) zu 
versenden. am einfachsten wäre das, wenn ich einen pointer (Uint8*) auf 
begin der struktur setze und die daten der reihe nach raussende. optimal 
geht das, wenn ich einen pointer auf struct_status_tx_8 setze. setze ich 
einen pointer auf struct_status_tx_16_A so werden natürlich die Lücken 
auch gesendet - das soll verhindert werden. natürlich kann ich die 
struktur so aufbauen wie in struct_status_tx_8, aber wenn ich dann einen 
uint16 wert incrementieren will, so tue ich mich schwer (neue temporäre 
uint16, aufteilen, zuweisen, etc.).

gibt es eine directive, womit man festlegt, dass diese lücken quasi 
nicht entstehen, bzw. die struktur im ganzen 8-bit organisiert bleibt?

verwendeter compiler: gcc

typedef struct
{
  Uint8 adr;      //  belegt bit 0..7
  Uint8 sta_lb;    //  belegt bit 8..15
  Uint8 sta_hb;    //  belegt bit 16..23
  Uint8 err;      //  belegt bit 24..31
}struct_status_tx_8;  //  sizeof() liefert 4 Bytes, korrekt!

typedef struct
{
  Uint8 adr;      //  belegt bit 0..7    //  bit 8..15 frei
  Uint16 sta;      //  belegt bit 16..31
  Uint8 err;      //  belegt bit 32..39  //  bit 40..47 frei
}struct_status_tx_16_A;  //  sizeof() liefert 6 Bytes, korrekt!

typedef struct
{
  Uint16 sta;      //  belegt bit 0..15
  Uint8 adr;      //  belegt bit 16..23
  Uint8 err;      //  belegt bit 24..31
}struct_status_tx_16_B;  //  sizeof() liefert 4 Bytes, korrekt!

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Thomas wrote:

> gibt es eine directive, womit man festlegt, dass diese lücken quasi
> nicht entstehen, bzw. die struktur im ganzen 8-bit organisiert bleibt?

Ja:
__attribute__((packed))

Aber: je nach Zielplattform wird dabei der Code entweder einfach nur
weniger effizient, aber manch Prozessor (insbesondere die RISC-Typen)
können dir dann auch schnell mal einen unaligned access trap schmeissen.
Allemal sinnvoller ist es, die Struktur gleich so aufzubauen, dass
zuerst alle 16-bit-Werte reingepackt werden und danach dann die
8-bit-Werte.  Damit hat man schlimmstenfalls am Ende ein einziges
Byte padding.

Autor: Thomas (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke, das funktioniert tatsächlich.

Nächste Frage; woher weiß man sowas?

Autor: Sven P. (haku) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Thomas wrote:
> Nächste Frage; woher weiß man sowas?

Soweit ich weiß:
__attribute__(()) gehört nicht direkt zum C-Standard, sondern ist ein 
Merkmal des verwendeten Compilers (ähnlich wie der ganze #pragma-Kram). 
Demnach findet man sowas z.B. im Handbuch des Compilers.

Autor: Olaf (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Danke, das funktioniert tatsächlich.

Aber nur zufaellig weil beide beteiligten CPUs bei dir High und Low
Byte in derselben Reihenfolge im Speicher ablegen...

Olaf

Autor: Kernighan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ Olaf

YMMD...

Gruss vom Indianer

Autor: Thomas (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Olaf: dem muss ich widersprechen.

Des passt schon so!

Autor: Marcus Harnisch (mharnisch) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jörg Wunsch wrote:
> Aber: je nach Zielplattform wird dabei der Code entweder einfach nur
> weniger effizient,

Ja.

> aber manch Prozessor (insbesondere die RISC-Typen) können dir dann
> auch schnell mal einen unaligned access trap schmeissen.

Nein. Das attribut ist doch gerade dazu da, dem Compiler zu sagen, dass 
er code erzeugen soll, der auf der gewählte Zielplatform die Daten 
zuverlässig liest.

Gruß
Marcus

Autor: Kernighan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Und was ist wenn diese Daten per Netzwerk (RS232, Ethernet, etc) von 
einer "Little Endian" zu einer "Big Endian" CPU übertragen werden?

Cheers,
Ritchie

Autor: Sven P. (haku) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Kernighan wrote:
> Und was ist wenn diese Daten per Netzwerk (RS232, Ethernet, etc) von
> einer "Little Endian" zu einer "Big Endian" CPU übertragen werden?

Das ist dann quasi scheißegal, weil zwischen Host-Byte-Order und 
Network-Byte-Order unterschieden wird, wobei letztere festgelegt ist. 
Dazu gibts dann in jeder guten Standardbibliothek 
Konvertierungsfunktionen.

Bei RS232 wird meistens immer zuerst das kleinste Bit übertragen.

Autor: Simon K. (simon) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sven Pauli wrote:
> meistens immer
Hehe, ja. Oder so! ;)

Autor: Michael Haberler (mah)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
also wenn Du die Kontrolle über das "wire format" hast, würde ichs 
umbauen, sodass Variable immer minimum alignment haben - offsets von 
16bit variablen immer modulo 2 = 0, 32bit Variable auf mod 4 = 0 usw

Sieh Dir mal zB die IP header an - zB 
http://www.faqs.org/rfcs/rfc791.html

wenns nicht passt - exlpizit padding bytes einfügen

umbauen auf "alle shorts/longs zuerst" geht  nicht immer elegant, zB 
wenn ein Längen- oder Variantenfeld drin ist

diese alignment-Technik hat ihren Grund - solche Protokollheader auf 
einer >8bit CPU auseinanderzuklamüsern ist schlimm, wenn du keine 16 & 
32bit operationen mehr verwenden kannst (ich durfte anno schnee ein 
Protokoll auf einer RISC-CPU dekodieren, bei denen longs auf einer 
24-bit-Grenze waren - danke, Bill!)

was auch geht statt einem compiler-spezifischen attribut: definier Dir 
Deine eigene "byte aligned" short, zB

typedef struct myshort_s {
    uint8_t     b1;
    uint8_t     b2;
} myshort;

diese struct sollte byte-aligned passen und du kannst sie statt einem 
short einsetzen, aber dann kannst Du erst wieder b1 und b2 separat 
verwursten - Makros helfen, machen es aber weder schöner noch schneller; 
byte order ist auch noch zu berücksichtigen.

-mah

ps: wenn ich ein wire-format entwerfen müsste:
- alignment wie oben
- type-length-value Notation verwenden 
(http://en.wikipedia.org/wiki/Type-length-value), das machts einfach zu 
verarbeiten und problemlos erweiterbar
- alles auf network byte order normieren

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.