Gepackte Bitfelder in C-Strukturen – GCC

Lesezeit: 2 Minuten

Benutzer-Avatar
Danny Cohen

Ich arbeite mit Strukturen in c unter Linux. Ich habe angefangen, Bitfelder und das Attribut “packed” zu verwenden, und bin auf ein seltsames Verhalten gestoßen:

struct __attribute__((packed)) {
    int a:12;
    int b:32;
    int c:4;
} t1;

struct __attribute__((packed))  {
    int a:12;
    int b;
    int c:4;
}t2;

void main()
{
    printf("%d\n",sizeof(t1)); //output - 6
    printf("%d\n",sizeof(t2)); //output - 7
}

Wie kommt es, dass beide Strukturen – die genau gleich sind – eine unterschiedliche Anzahl von Bytes benötigen?

  • Da t2::b ist garantiert ein eindeutiger Speicherort? Denken Sie an Datenrennen.

    – Kerrek SB

    13. September 2014 um 11:26 Uhr

  • das Ergebnis von sizeof muss mit gedruckt werden %zu

    – phuklv

    8. Juli 2021 um 0:53 Uhr

Benutzer-Avatar
Matte

Ihre Strukturen sind nicht “genau gleich”. Ihr erstes hat drei aufeinanderfolgende Bitfelder, das zweite hat ein Bitfeld, ein (Nicht-Bitfeld) int und dann ein zweites Bitfeld.

Dies ist von Bedeutung: Aufeinanderfolgende Bitfelder (mit einer Breite ungleich Null) werden zu einem einzigen zusammengeführt Speicherortwährend ein Bit-Feld gefolgt von einem Nicht-Bit-Feld unterschiedliche Speicherstellen sind.

Ihre erste Struktur hat einen einzigen Speicherort, Ihre zweite hat drei. Sie können die Adresse des nehmen b member in Ihrer zweiten Struktur, nicht in Ihrer ersten. Zugriffe auf die b Mitglied rennt nicht mit Zugriffen auf die a oder c in Ihrer zweiten Struktur, aber sie tun es in Ihrer ersten.

Wenn man ein Nicht-Bit-Feld (oder ein Bit-Feld der Länge Null) hat, direkt nachdem ein Bit-Feld-Mitglied es gewissermaßen “schließt”, dann folgt ein anderer/unabhängiger Speicherort/ein anderes/unabhängiges Objekt. Der Compiler kann Ihre nicht “packen”. b Mitglied innerhalb des Bitfelds, wie es in der ersten Struktur der Fall ist.

struct t1 // 6 bytes
{
    int a:12; // 0:11
    int b:32; // 12:43
    int c:4;  // 44:47
}__attribute__((packed));

struct t1 // 7 bytes
{
    int a:12; // 0:11
    int b;    // 16:47
    int c:4;  // 48:51
}__attribute__((packed));

Das regelmäßige int b muss an einer Bytegrenze ausgerichtet werden. Es gibt also eine Polsterung davor. Wenn Sie setzen c gleich neben a diese Polsterung wird nicht mehr benötigt. Sie sollten dies wahrscheinlich tun, da der Zugriff auf nicht Byte-ausgerichtete Ganzzahlen wie int b:32 ist langsam.

  • as accessing non-byte-aligned integers like int b:32 is slow Quelle? definiere langsam. Verschiebt und maskiert es nicht einfach den Speicherwert?

    – Alexis

    7. Juli 2021 um 11:22 Uhr

  • Es hängt davon ab, aber es wird nie so schnell sein wie die Byte-Ausrichtung. Wie langsam (oder sogar wie wir langsam definieren) hängt von der Anwendung, dem Compiler usw. ab.

    – Johannes Zwinck

    8. Juli 2021 um 11:14 Uhr

  • Verstanden, ich vermute, es geht nur um schnelles Umschalten + Maske.

    – Alexis

    8. Juli 2021 um 15:33 Uhr

  • Es kann nur “shift+mask” sein, wenn der gesamte Wert in ein einzelnes Register passt. Aber es gibt viele Vielleichts. Vielleicht passt es nicht in ein einzelnes Register (plattformabhängig), also sind es 2 Verschiebungen, 2 Masken und ein oder zwischen 2 Registern. Vielleicht ist diese Struktur an einer Operation beteiligt, die vorher hätte vektorisiert werden können, aber jetzt nicht (oder kann es sein, aber mit nicht ausgerichteten Lasten). Viele Vielleicht.

    – Matthäus M.

    24. Juni um 14:39 Uhr

1343740cookie-checkGepackte Bitfelder in C-Strukturen – GCC

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy