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
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
13437400cookie-checkGepackte Bitfelder in C-Strukturen – GCCyes
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