2016-08-05 66 views
2
struct A 
{ 
    uint32_t var1; 
    uint32_t var2; 
    uint32_t var3; 
    uint32_t var4; 
    uint32_t var5; 
}; 

In der oben genannten Struktur nicht Compiler nicht auffüllen und weist 20 Bytes.Struktur Padding auf 64-Bit-Maschine

jetzt haben wir eine andere Struktur, die eine 8-Byte-Variable anstelle von zwei 4 Bytes enthält. In diesem Fall packt Compiler und weist dieser Struktur 24 Bytes zu.

struct B 
{ 
    uint32_t var1; 
    uint32_t var2; 
    uint32_t var3; 
    uint64_t var5; 
}; 

Warum gibt es ein solches Verhalten? Wenn der Compiler die Daten in 8-Byte-Grenzen ausrichtet, dann sollte in der 1. Struktur ein Padding von 4 Bytes vorhanden sein, und in diesem Fall sollte die 2. Struktur nicht auffüllen. und auch, wenn Compiler die Daten in die 4-Byte-Grenze ausrichten, warum gibt es Padding von 4 Byte in der 2. Struktur?

Compiler GCC Plattform: 64-Bit-Linux, x86_64

+8

Die Ausrichtung Anforderung der Struktur ist die Ausrichtung des Elements mit der strengsten Ausrichtung Anforderung. Auf Ihrer C-Implementierung hat 'uint64_t' strengere Anforderungen als 'uint32_t'. – EOF

+4

Mögliches Duplikat von [Warum benötigt ein uint64 \ _t bei Verwendung in einer Klasse mehr Speicher als 2 uint32 \ _t? Und wie kann man das verhindern?] (Http://stackoverflow.com/questions/26381206/why-does-an-uint64-t-needs-more-memory-than-2-uint32-ts-when-usedin-in- a-class-a) – Mars

+0

Ohne Padding würde der Uint64_t bei Offset 12 beginnen. Das verschiebt es falsch, kein Vielfaches von 8, also fügt der Compiler 4 Byte Padding ein, um es auf Offset 16 zu bringen. 16 + 8 = 24. Es ist kein zusätzliches Padding erforderlich, es ist immer noch ausgerichtet, wenn es in einem B [] gespeichert ist, also ist 24 gut genug. –

Antwort

4

Die Regel für die Ausrichtung (auf x86 und x86_64) besteht in der Regel darin, eine Variable auf ihre Größe auszurichten.

Mit anderen Worten werden 32-Bit-Variablen auf 4 Bytes ausgerichtet, 64-Bit-Variablen auf 8 Bytes, usw.

in Ihrem zweiten Fall 4 Bytes padding addiert zwischen

uint32_t var3; 
uint64_t var5; 

, um var5 auf 8 Bytes auszurichten.

Aus diesem Grund ist es besser, Datenelemente vom größten zum kleinsten zu bestellen (aber es ist nicht so einfach wegen Datenlokalität, Lesbarkeit usw.).

1

Zu allererst Struktur Ausrichtung ist keine exakte Wissenschaft, und kann auf die Architektur und Compiler abhängen.

In vielen Fällen werden alle Strukturelemente entsprechend der größten Variablen (in Byte) aufgefüllt. Auf Ihrer ersten Struktur sind alle Variablen uint32_t, was 4 Byte Länge ist. Dann ist Ihre Strukturgröße gleich sizeof(uint32_t) * 5 = 4 * 5 = 20.

Auf Ihrer zweiten Struktur ist das größte Element uint64_t, das eine Größe von 8 Bytes hat. Also werden alle Elemente entsprechend 8 Bytes aufgefüllt.

Die ersten beiden uint32_t sind zusammen gepolstert, aber die dritte kann nicht richtig aufgefüllt werden: Wenn sie mit der nächsten Ganzzahl aufgefüllt wird, wird die uint64_t in zwei geteilt! Also hat der Compiler beschlossen, diese uint32_t auf sich beruhen zu lassen, um die Teilung der uint64_t zu vermeiden. Hier

ist ein Beispiel mit Ihren Strukturen und was die Adresse aller Variablen sein könnte:

struct A 
{ 
    uint32_t var1; /* ..00 */ 
    uint32_t var2; /* ..04 */ 
    uint32_t var3; /* ..08 */ 
    uint32_t var4; /* ..12 */ 
    uint32_t var5; /* ..16 */ 
}; 

struct B 
{ 
    uint32_t var1; /* ..00 */ 
    uint32_t var2; /* ..04 */ 
    uint32_t var3; /* ..08 */ 
    uint64_t var5; /* ..16 */ 
}; 
0
#include <stdio.h> 

typedef struct __atribute__((packed)) A { 
    uint32_t var1; 
    uint32_t var2; 
    uint32_t var3; 
    uint32_t var4; 
    uint32_t var5; 
} A ; 


typedef struct __atribute__((packed)) B { 
    uint32_t var1; 
    uint32_t var2; 
    uint32_t var3; 
    uint64_t var4; 
} B; 


int main() 
{ 
    printf("sizeof(A): {%d} sizeof(B): {%d}", A, B); 

    return 0; 
} 

dies versuchen, es funktioniert für mich

0

Obwohl Compiler Pad frei ist oder nicht Pad, wie sie es für richtig halten, in der Regel werden sie Variablen an einer Grenze ausrichten, die ein Vielfaches der Variablengröße ist.

Im Falle eines struct basiert die Auffüllung auf der Größe des größten primitiven Elements. Im Fall der zweiten struct B wäre dies var5, was vom Typ uint64_t ist.

Das Layout struct B mit dem impliziten Polsterung ist wie folgt:

struct B 
{ 
    uint32_t var1;  // offset 0 
    uint32_t var2;  // offset 4 
    uint32_t var3;  // offset 8 
    uint32_t padding; // offset 12 
    uint64_t var5;  // offset 16 
}; 

Wenn var5 sofort waren var3 zu folgen, ist es bei Byte 12 versetzt sein würde, was es braucht, damit nicht ein Vielfaches von 8 ist um 4 Bytes der Auffüllung nach var3 zu sein, um var5 zu erlauben, richtig ausgerichtet zu werden.

Im Fall struct A sind alle Felder 4 Byte groß, so dass kein Padding erforderlich ist.Wenn Sie ein Array dieses Typs erstellen, zum Beispiel struct A a[5], a[1] wäre 20 Bytes nach a[0], a[2] wäre 20 Bytes nach a[1], und so weiter. Das Hinzufügen von Auffüllung zu struct A würde Platz verschwenden, da alle Unterfelder noch auf der 4-Byte-Grenze ausgerichtet sind, die sie benötigen.

0

Die Polsterung in Ihrem struct B ist mit ziemlicher Sicherheit am Ende nicht, aber nach dem dritten Elemente 32-Bit:

struct B 
{ 
    uint32_t var1; 
    uint32_t var2; 
    uint32_t var3; 
    // padding here 
    uint64_t var5; 
}; 

Dies liegt daran, var1 durch var3-24 Bytes addiert, die durch nicht teilbar ist 8. Ihr Compiler will ein 8-Byte-integer-Typ auf eine Adresse sein, durch 8 teilbar

Sie werden auch Polsterung am Ende der Struktur in einer Situation wie diese:

struct C 
{ 
    uint64_t memb1; 
    uint32_t memb2; 
    // Padding here 
}; 

Das Polster ist aus Gründen der memb1 Ausrichtung in einer Anordnung von struct C:

struct C c_array[13]; 

natürlich c_array[0].memb1 ausgerichtet ist, da sie an der Basisadresse des Arrays ist. Aber was ist mit c_array[1].memb1? Ohne die Auffüllung in der Struktur wäre es nicht ausgerichtet.

C ist so definiert, dass zwischen Array-Elementen kein Padding hinzugefügt werden darf; Die Elemente eines Arrays sind eng zugeordnet. Wenn ein Padding erforderlich ist, muss es daher in den Elementtyp eingepasst werden. Das Layout von Strukturen muss mögliche Array-Aggregationen berücksichtigen.