[C] Größe / Ausrichtung von structs

ThePsycho

Vice Admiral Special
Mitglied seit
10.03.2003
Beiträge
637
Renomée
1
Hallo,

ich werkel immernoch ein wenig am Kernel rum und bin auf folgendes gestoßen:

Ich habe ein struct:

Code:
struct oha {
  u8 a : 4,
       b : 4,
  u8 c : 4,
       d : 4,
  u32 e : 30,
         f : 2
}

Wie man sich leicht ausrechnen kann sind das 6 Bytes. Ein sizeof(struct oha) liefert aber 8 (auf 32 Bit x86) - ist das so festegelegt? Wird immer auf eine 4-Byte-Größe aufgerundet? Oder ist das gar eine Eigenheit des GCC (Version 4.1 btw.)?

Weitere Frage:
Code:
char x[8];

struct oha *p = (struct oha *) x;

Welche Bytes bleiben dann unbenutzt? x[0 + 1] oder x[6 + 7]?

Danke.
 
Zuletzt bearbeitet:
Wie man sich leicht ausrechnen kann sind das 6 Bytes. Ein sizeof(struct oha) liefert aber 8 (auf 32 Bit x86) - ist das so festegelegt? Wird immer auf eine 4-Byte-Größe aufgerundet?

Das ist Absicht, du bist auf einer Maschine, deren Worte 32bit breit sind.
Teilweise ist es sogar von Vorteil noch mehr "Füllbytes" einzubringen (Stichwort Cachezeilenbreite)

Weitere Frage:
Code:
char x[8];

struct oha *p = (struct oha *) x;

Welche Bytes bleiben dann unbenutzt? x[0 + 1] oder x[6 + 7]?
Probiere es aus...
x[0]=0;
x[1]=1;
...
x[7]=7;
und danach greife mal auf die Elemente deines Structs zu und gebe diese ggf. hex aus.

Gruß,
TheJudger
 
__attribute((packed)) sollte dir hier weiter helfen:

struct oha {
...
} __attribute((packed));

Damit verhinderst du das alignment der struct-member.
 
Ausprobieren ist klar, meine Frage zielte eher darauf, ob es der C-Standard fest vorschreibt, wie genau das auszusehen hat.
Unklar ausgedrückt, sry.
Was der C-Standard hier vorschreibt, müsstest Du im selben nachlesen.
Es ist auf jeden Fall abhängig vom Compiler und der Zielmaschine.
Das Verhindern des Auffüllens wird auch unterschiedlich gehandhabt. Mal sind es spezifische Anweisungen wie __attribute((packed)), bei einem anderen Compiler ist es #pragma(packed) oder per Option beim Compileraufruf.
Auf Strukturen und Alignment muss man jedenfalls immer aufpassen, wenn entsprechende Daten zwischen verschiedenen (Prozessor-) Systemen übertragen werden müssen. Auch die Reihenfolge der Datenbytes kann eine Rolle spielen, Stichworte Big- und Little-Endian.
 
Da ich den Standard jetzt nicht vor mir liegen habe, sind die folgenden Aussagen ohne Garantie. Aber wie Ray schon geschrieben hat, ist das Alignment von der Zielplattform abhängig. Und damit kann der Standard garnichts vorschreiben, denn der ist Hardware-unabhängig. Und das "Problem" hier ist auch nicht das Alignment des struct sondern seiner Member. Die u8 Teile werden wahrscheinlich an 8 Bit Adressen ausgerichtet, der u32 Teil hingegen an an einer 32 Bit Adresse. Das heißt das erste Element wird an einer 32 Bit Adresse ausgerichtet, das zweite an der nächsten 8 Bit Adresse und das dritte dann an der nächsten 32 Bit Adresse. Du hast also ein Lücke innerhalb des struct, nicht am Anfang oder Ende.
 
Also wenn du Daten als struct irgendwo hineinschreibst, dann musst du sie auch als struct wieder herauslesen. Alles andere ist Pfuscherei. Das kann zwar momentan hinhauen, aber wenn du dann den Compiler wechselst, haut alles nicht mehr hin und keiner weiß wieso.
 
Ok, die Frage ist ja zum Glück inzwischen, durch "__attribute((packed))", nicht mehr relevant.
Im Linux-Kernel wird ja allgemein von GCC ausgegangen, dann werde ich das auch so halten.

Danke jedenfalls für die Antworten.

@andr_gin
Keine Sorge, sowas hatte ich nicht vor. :)
 
Naja bei uns hat das sogar unser unfähiger Programmierlehrer in seinem Beispiel gemacht und die ganzen Leute, die seit 1-2 Monaten C lernen, haben sich das ganze Programm damit herumschlagen können, dass die Daten nicht stimmen (Endianess), weil einfach seine read-Funktion Mist geliefert hat.
 
Zurück
Oben Unten