Erwägen:
struct mystruct_A
{
char a;
int b;
char c;
} x;
struct mystruct_B
{
int b;
char a;
} y;
Die Größen der Strukturen betragen 12 bzw. 8.
Sind diese Strukturen gepolstert oder gepackt?
Wann findet Polsterung oder Verpackung statt?
padding
macht die Dinge größer.packing
macht die Dinge kleiner. Ganz anders.Antworten:
Klotzen ausrichtet Strukturelemente zu „natürlichen“ Adressgrenzen - sagen wir,
int
würden Mitglieder Offsets haben, die sichmod(4) == 0
auf 32-Bit - Plattform. Das Auffüllen ist standardmäßig aktiviert. Es fügt die folgenden "Lücken" in Ihre erste Struktur ein:Das Packen hingegen verhindert, dass der Compiler ein Padding ausführt - dies muss explizit angefordert werden - unter GCC ist es
__attribute__((__packed__))
das Folgende:würde eine Struktur der Größe
6
auf einer 32-Bit-Architektur erzeugen .Ein Hinweis: Der nicht ausgerichtete Speicherzugriff ist bei Architekturen, die dies zulassen (wie x86 und amd64), langsamer und bei Architekturen mit strikter Ausrichtung wie SPARC ausdrücklich verboten .
quelle
( Die oben genannten Antworten erklärt den Grund , ganz klar, aber es scheint über die Größe der Polsterung nicht ganz klar, so werde ich eine Antwort hinzufügen nach dem , was ich daraus gelernt The Lost Art of Structure Verpackung hat es nicht Grenze entwickelte sich zu
C
, aber gilt auch fürGo
,Rust
. )Memory Align (für Struktur)
Regeln:
Beispiel: Auf einem 64-Bit-System
int
sollte an einer Adresse beginnen, die durch 4 undlong
durch 8short
durch 2 teilbar ist .char
undchar[]
sind speziell, könnte jede Speicheradresse sein, so dass sie nicht vor ihnen aufgefüllt werden müssen.struct
abgesehen von der Ausrichtung für jedes einzelne Element wird die Größe der gesamten Struktur selbst durch Auffüllen am Ende auf eine Größe ausgerichtet, die durch die Größe des größten einzelnen Elements teilbar ist.Beispiel: Wenn das größte Mitglied der Struktur
long
durch 8 teilbar ist,int
dann durch 4,short
dann durch 2.Reihenfolge des Mitglieds:
stu_c
undstu_d
aus dem folgenden Beispiel die gleichen Elemente, jedoch in unterschiedlicher Reihenfolge, und führen zu einer unterschiedlichen Größe für die beiden Strukturen.Adresse im Speicher (für struct)
Regeln:
beginnt bei
(n * 16)
Bytes. ( Im folgenden Beispiel sehen Sie, dass alle gedruckten Hex-Adressen von Strukturen mit enden0
. )Grund : Das möglicherweise größte einzelne Strukturelement ist 16 Byte (
long double
).char
Mitgliedenthält, kann ihre Adresse an einer beliebigen Adresse beginnen.Leerer Raum :
B. in
test_struct_address()
folgenden werden die variablenx
befindet sich zwischen benachbarten structg
undh
.Unabhängig davon, ob
x
deklarierth
wird, ändert sich die Adresse nicht. Verwenden Siex
einfach den leeren Speicherplatz, derg
verschwendet wurde.Ähnliches gilt für
y
.Beispiel
( für 64-Bit-System )
memory_align.c :
Ausführungsergebnis -
test_struct_padding()
:Ausführungsergebnis -
test_struct_address()
:Somit ist der Adressstart für jede Variable g: d0 x: dc h: e0 y: e8
quelle
<The Lost Art of C Structure Packing>
erklärt die Regeln ziemlich gut, obwohl es etwas länger ist als diese Antwort. Das Buch ist frei online verfügbar: catb.org/esr/structure-packingIch weiß, dass diese Frage alt ist und die meisten Antworten hier das Auffüllen sehr gut erklären, aber während ich versuchte, sie selbst zu verstehen, dachte ich, dass ein "visuelles" Bild von dem, was passiert, hilfreich ist.
Der Prozessor liest den Speicher in "Blöcken" einer bestimmten Größe (Wort). Angenommen, das Prozessorwort ist 8 Byte lang. Der Speicher wird als große Reihe von 8-Byte-Bausteinen betrachtet. Jedes Mal, wenn Informationen aus dem Speicher abgerufen werden müssen, erreicht es einen dieser Blöcke und ruft sie ab.
Wie im obigen Bild zu sehen ist, spielt es keine Rolle, wo sich ein Zeichen (1 Byte lang) befindet, da es sich in einem dieser Blöcke befindet und die CPU nur 1 Wort verarbeiten muss.
Wenn wir mit Daten arbeiten, die größer als ein Byte sind, wie z. B. ein 4-Byte-Int oder ein 8-Byte-Double, hängt die Art und Weise, wie sie im Speicher ausgerichtet sind, davon ab, wie viele Wörter von der CPU verarbeitet werden müssen. Wenn 4-Byte-Blöcke so ausgerichtet sind, dass sie immer in das Innere eines Blocks passen (die Speicheradresse ist ein Vielfaches von 4), muss nur ein Wort verarbeitet werden. Andernfalls könnte ein Block von 4 Bytes einen Teil von sich selbst in einem Block und einen Teil von einem anderen haben, so dass der Prozessor 2 Wörter verarbeiten muss, um diese Daten zu lesen.
Gleiches gilt für ein 8-Byte-Double, außer dass es sich jetzt in einem Speicheradressen-Vielfachen von 8 befinden muss, um sicherzustellen, dass es sich immer in einem Block befindet.
Dies berücksichtigt ein 8-Byte-Textverarbeitungsprogramm, das Konzept gilt jedoch auch für andere Wortgrößen.
Beim Auffüllen werden die Lücken zwischen diesen Daten gefüllt, um sicherzustellen, dass sie mit diesen Blöcken ausgerichtet sind, wodurch die Leistung beim Lesen des Speichers verbessert wird.
Wie in anderen Antworten angegeben, ist der Raum jedoch manchmal wichtiger als die Leistung selbst. Vielleicht verarbeiten Sie viele Daten auf einem Computer, der nicht viel RAM hat (Swap Space könnte verwendet werden, aber es ist VIEL langsamer). Sie können die Variablen im Programm anordnen, bis das geringste Auffüllen erfolgt ist (wie in einigen anderen Antworten deutlich gezeigt wurde). Wenn dies jedoch nicht ausreicht, können Sie das Auffüllen explizit deaktivieren. Dies ist das Packen .
quelle
Strukturpackung unterdrückt Strukturpolsterung, Polsterung, die verwendet wird, wenn die Ausrichtung am wichtigsten ist, Packung, die verwendet wird, wenn der Platz am wichtigsten ist.
Einige Compiler bieten
#pragma
die Möglichkeit , das Auffüllen zu unterdrücken oder es auf n Bytes zu packen. Einige bieten dazu Schlüsselwörter an. Im Allgemeinen hat Pragma, das zum Ändern des Strukturauffüllens verwendet wird, das folgende Format (abhängig vom Compiler):Beispielsweise stellt ARM das
__packed
Schlüsselwort zum Unterdrücken des Strukturauffüllens bereit . Lesen Sie Ihr Compiler-Handbuch, um mehr darüber zu erfahren.Eine gepackte Struktur ist also eine Struktur ohne Polsterung.
Im Allgemeinen werden gepackte Strukturen verwendet
Platz sparen
Formatieren einer Datenstruktur für die Übertragung über ein Netzwerk mithilfe eines Protokolls (dies ist natürlich keine gute Vorgehensweise, da Sie
sich mit Endianness befassen müssen).
quelle
Polsterung und Verpackung sind nur zwei Aspekte derselben Sache:
Unter der
mystruct_A
Annahme einer Standardausrichtung von 4 wird jedes Mitglied auf ein Vielfaches von 4 Bytes ausgerichtet. Da die Größe vonchar
1 ist, beträgt die Auffüllung füra
undc
4 - 1 = 3 Bytes, während keine Auffüllung erforderlich ist, fürint b
die bereits 4 Bytes vorhanden sind. Es funktioniert genauso fürmystruct_B
.quelle
Das Packen von Strukturen erfolgt nur, wenn Sie Ihren Compiler explizit anweisen, die Struktur zu packen. Polsterung ist das, was Sie sehen. Ihr 32-Bit-System füllt jedes Feld mit der Wortausrichtung auf. Wenn Sie Ihrem Compiler gesagt hätten, er solle die Strukturen packen, wären sie 6 bzw. 5 Byte. Tu das aber nicht. Es ist nicht portabel und lässt Compiler viel langsameren (und manchmal sogar fehlerhaften) Code generieren.
quelle
Es gibt kein Aber! Wer das Thema erfassen will, muss folgende tun:
quelle
Regeln für das Auffüllen:
Warum Regel 2: Betrachten Sie die folgende Struktur:
Wenn wir ein Array (mit 2 Strukturen) dieser Struktur erstellen, ist am Ende kein Auffüllen erforderlich:
Daher ist die Größe von struct = 8 Bytes
Angenommen, wir würden eine andere Struktur wie folgt erstellen:
Wenn wir ein Array dieser Struktur erstellen, gibt es zwei Möglichkeiten, die Anzahl der am Ende erforderlichen Auffüllbytes.
A. Wenn wir am Ende 3 Bytes hinzufügen und es für int und nicht Long ausrichten:
B. Wenn wir am Ende 7 Bytes hinzufügen und für Long ausrichten:
Die Startadresse des zweiten Arrays ist ein Vielfaches von 8 (dh 24). Die Größe der Struktur = 24 Bytes
Durch Ausrichten der Startadresse des nächsten Arrays der Struktur an einem Vielfachen des größten Elements (dh wenn wir ein Array dieser Struktur erstellen möchten, muss die erste Adresse des zweiten Arrays an einer Adresse beginnen, die ein Vielfaches ist Hier können wir mit 24 (3 * 8) die Anzahl der am Ende erforderlichen Füllbytes berechnen.
quelle
Die Datenstrukturausrichtung ist die Art und Weise, wie Daten im Computerspeicher angeordnet und abgerufen werden. Es besteht aus zwei getrennten, aber verwandten Themen: Datenausrichtung und Auffüllen der Datenstruktur . Wenn ein moderner Computer von einer Speicheradresse liest oder in diese schreibt, geschieht dies in wortgroßen Blöcken (z. B. 4-Byte-Blöcken auf einem 32-Bit-System) oder größer. Datenausrichtung bedeutet, dass die Daten an einer Speicheradresse abgelegt werden, die einem Vielfachen der Wortgröße entspricht. Dies erhöht die Systemleistung aufgrund der Art und Weise, wie die CPU mit dem Speicher umgeht. Um die Daten auszurichten, müssen möglicherweise einige bedeutungslose Bytes zwischen dem Ende der letzten Datenstruktur und dem Beginn der nächsten Daten eingefügt werden. Dies ist das Auffüllen der Datenstruktur.
quelle