mikrocontroller.net

Forum: Compiler & IDEs packed bei verschachtelten Strukturen


Autor: Rainer K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Liebe Community,

zuerst ein Beispiel:

typedef struct{
 uint8_t one;
 uint8_t two;
 uint8_t three;
} MEMBER_STRUCT;

struct myStruct{
 uint32_t member1;
 uint8_t  member2;
 MEMBER_STRUCT member3;
}__attribute__((__packed__));
typedef struct myStruct MYSTRUCT;

MYSTRUCT instanceVariable;


Ohne jetzt drüber zu diskutieren das ich hier unaligned 
Speicherzugriffen machen muss... Was passiert mit member3? Wenn ich 
MEMBER_STRUCT getrennt von myStruct verwende wird vermutlich ein Byte 
gepadded, da so ein Langwortzugriff möglich ist. Wir das padding Byte 
bei member3 auch eingefügt, selbst wenn es eine "Unter-"Struct einer 
packed Struct ist?

Danke und Gruß, Rainer

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Rainer K. schrieb:

> Ohne jetzt drüber zu diskutieren das ich hier unaligned
> Speicherzugriffen machen muss... Was passiert mit member3? Wenn ich
> MEMBER_STRUCT getrennt von myStruct verwende wird vermutlich ein Byte
> gepadded, da so ein Langwortzugriff möglich ist. Wir das padding Byte
> bei member3 auch eingefügt, selbst wenn es eine "Unter-"Struct einer
> packed Struct ist?


Hmm
Gute Frage.
Der C-Standard hält sich bei derartigen Sachen sehr bedeckt. Ausser "Ja, 
es kann Padding geben" ist da sehr wenig definiert.

Hast du schon versucht mittels sizeof zu Erkentnissen zu kommen, wie das 
dein Compiler handhabt?

Autor: Rainer K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Habe den sizeof Test mal gemacht, ich hatte  diesen vor geraumer Zeit 
mit einer älteren GCC Version schon durchgeführt und ich bin mir sicher 
das dort alle Padding-Bytes beseitigt wurden, auch bei Unterstrukturen. 
Erstaunlicher Weise ist das bei meiner aktuellen Version 4.4.1 nicht der 
Fall. In dem konkreten Beispiel wird member3 auf 4 Byte aufgeblasen.

Einmal öfter zeigt sich das man möglichst Compilerunabhänigen Code 
schreiben sollte, dies ist aber in der Realität oft nur bedingt möglich. 
:(

Danke für den Hinweis. :)

Autor: Andreas B. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich würde mal sagen, dass das Padding von MEMBER_STRUCT durch das packed 
auf myStruct nicht beinflusst wird und das so das einzige ist, was Sinn 
macht. Was sollte sonst der Compiler bei einem Zugriff über Zeiger auf 
MEMBER_STRUCT machen? Das kann ja nicht davon abhängen wo das 
MEMBER_STRUCT liegt.

Ich seh grad, dass das auch explizit in der gcc-Dokumentation steht:

>     In the following example `struct my_packed_struct''s members are
>     packed closely together, but the internal layout of its `s' member
>     is not packed--to do that, `struct my_unpacked_struct' would need
>     to be packed too.
>
>          struct my_unpacked_struct
>           {
>              char c;
>              int i;
>           };
>
>          struct _attribute_ ((_packed_)) my_packed_struct
>            {
>               char c;
>               int  i;
>               struct my_unpacked_struct s;
>            };

Autor: Marcus Harnisch (mharnisch) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Rainer K. schrieb:
> Was passiert mit member3? Wenn ich MEMBER_STRUCT getrennt von
> myStruct verwende wird vermutlich ein Byte gepadded, da so ein
> Langwortzugriff möglich ist.

Das kommt auf die Architektur an. Hast Du eine spezielle im Sinn?

Andreas B. schrieb:
> Ich würde mal sagen, dass das Padding von MEMBER_STRUCT durch das
> packed auf myStruct nicht beinflusst wird und das so das einzige
> ist, was Sinn macht.

Ist aber auch nicht so intuitiv. Du hast dann u.U. padding zwischen
einem Element der umgebenden packed Struktur und dem unpacked
Strukturelement. Zu wem gehört das Padding jetzt? Zur umgebenden
Struktur kann es nicht gehören, da diese per Definition kein Padding
enthalten kann. Zum unpacked Element kann es auch nicht gehören, da
sich dann sizeof(member) ändern würde.

Die richtige Antwort des Compilers ist diese:
"packed_structs.c", line 83: Error:  #1032: Definition of nested
        anonymous struct in packed "struct myStruct" must be __packed
   MEMBER_STRUCT member3;
                 ^
packed_structs.c: 0 warnings, 1 error

Gruß
Marcus

Autor: sebastians (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Zum unpacked Element kann es auch nicht gehören, da
>sich dann sizeof(member) ändern würde.
Wieso "ändern"? Gegenüber welcher Referenzgröße?
sizeof(MEMBER_STRUCT) ist 4 wenn man es im normalen Kontext verwendet, 
also gehört das pad-byte zu MEMBER_STRUCT, wo ist das Problem?

Autor: Marcus Harnisch (mharnisch) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
sebastians schrieb:
>>Zum unpacked Element kann es auch nicht gehören, da
>>sich dann sizeof(member) ändern würde.
> Wieso "ändern"? Gegenüber welcher Referenzgröße?

Dem alleinstehenden MEMBER_STRUCT. sizeof(MEMBER_STRUCT) wäre dann
nicht mehr gleich sizeof(MYSTRUCT.member3).

> sizeof(MEMBER_STRUCT) ist 4 wenn man es im normalen Kontext verwendet,
> also gehört das pad-byte zu MEMBER_STRUCT, wo ist das Problem?

Wenn man davon ausgeht, dass MEMBER_STRUCT ein abschließendes Padding
Byte enthält, "da so ein Langwortzugriff möglich ist", dann gelten
möglicherweise auch irgendwelche Einschränkungen bezüglich des
Alignments. Nehmen wir also mal an, das Alignment von MEMBER_STRUCT
wäre nicht beliebig (!=1). Dann hinge es vom Alignment der Elemente in
myStruct ab, ob Padding zwischen member2 und member3 eingefügt
wird. Die Anzahl der Padding Bytes müsste unter Umständen sogar für
verschiedene Instanzen von MYSTRUCT unterschiedlich sein, abhängig
davon, an welcher Adresse member2 tatsächlich liegt. Es sei denn, dass
Alignment von member3 bestimmt das Alignment von MYSTRUCT, was
wiederum dem Gedanken von packed widerspricht.

Gruß
Marcus

Autor: Rainer K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hmm also GCC padded bei "nested structs", der KEIL Compiler aber sehr 
wohl. Keiner von beiden gibt eine Warning oder gar error aus. Unschön 
das es hier eine Diskrepanz gibt.

Und ganz intuitiv finde ich das Verhalten vom GCC nicht, denn ich dachte 
eigentlich, das er bei einem typedef im grunde genommen die variablen 
der inneren Struct (member3) quasi an die entsprechende Stelle kopiert, 
quasi soetwas baut:
struct myStruct{
 uint32_t member1;
 uint8_t  member2;
 uint8_t one;
 uint8_t two;
 uint8_t three;
}__attribute__((__packed__));
typedef struct myStruct MYSTRUCT;

Sollte Member 3 noch tiefer durch typedefs verschachtelt sein, würde ich 
erwarten das er soweit auflöst bis er auf die integralen Datentypen 
kommt. Folglich hätte man nur noch (reell) eine Struktur die aus 
integralen Datentypen besteht, wenn ich diese jetzt packed deklariere 
gibt es kein Padding. Das würde ich intuitiv erwarten. GCC tut es nicht. 
Danke an der Stelle an Andreas B. für das posten der Stelle aus der GCC 
Doku. :)

Ich habe in Ansi-c Standard geschaut, da steht quasi nicht viel zu - es 
wird quasi als Compiler dependent definiert.

Autor: Marcus Harnisch (mharnisch) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Rainer K. schrieb:
> Hmm also GCC padded bei "nested structs", der KEIL Compiler aber sehr
> wohl.

?

> Keiner von beiden gibt eine Warning oder gar error aus.

Was ist denn "der KEIL Compiler"? Die von mir zitierte Fehlermeldung
stammt aus dem Keil MDK-ARM.

> Sollte Member 3 noch tiefer durch typedefs verschachtelt sein, würde ich
> erwarten das er soweit auflöst bis er auf die integralen Datentypen
> kommt. Folglich hätte man nur noch (reell) eine Struktur die aus
> integralen Datentypen besteht, wenn ich diese jetzt packed deklariere
> gibt es kein Padding. Das würde ich intuitiv erwarten.

Aber das kann doch gar nicht gehen. Member3 wäre dann nicht mehr
typkompatibel zu anderen Instanzen von MEMBER_STRUCT.

Gruß
Marcus

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Rainer K. schrieb:

> kommt. Folglich hätte man nur noch (reell) eine Struktur die aus
> integralen Datentypen besteht, wenn ich diese jetzt packed deklariere
> gibt es kein Padding. Das würde ich intuitiv erwarten.

Ich nicht.

Denn ich erwarte eigentlich, dass
typedef struct{
 uint8_t one;
 uint8_t two;
 uint8_t three;
} MEMBER_STRUCT;

struct myStruct{
 uint32_t member1;
 uint8_t  member2;
 MEMBER_STRUCT member3;
}__attribute__((__packed__));
typedef struct myStruct MYSTRUCT;

  MYSTRUCT       mitMember;
  MEMBER_STRUCT  nurMember;

  memcpy( &mitMember.member3, &nurMember, sizeof( MEMBER_STRUCT ) );

  memcpy( &nurMember, &mitMember.member3, sizeof( MEMBER_STRUCT ) );

korrekt funktioniert.
Das hinzufügen eines packed Attributes darf daran nichts ändern. 
Schliesslich habe ich es immer mit der gleichen MEMBER_STRUCT zu tun.

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.