2012-10-12 1 views
7

Warum wird das Konzept des Auffüllens nur hinzugefügt, wenn mehrere Elemente einer Struktur vorhanden sind und warum es nicht enthalten ist, wenn ein einzelnes Mitglied des grundlegenden Datentyps vorhanden ist?Warum wird das Padding für mehrere Datenelemente von Strukturen und nicht für einzelne Elemente hinzugefügt?

, wenn wir auf einem 32-Bit-Maschine betrachten

struct 
{ 
    char a; 
} Y; 

Es gibt keine Polsterung und sizeof Y kommt auf 1 Byte.

Wenn wir diese Struktur

struct 
{ 
    char a; 
    int b; 
} X; 

Sizeof X wird 8bytes betrachten.

Meine Frage ist Warum wurde Padding im zweiten Fall hinzugefügt? Wenn es für den effizienten Zugriff durch die Maschine, die normalerweise Daten in Blöcken von Vielfachen von 4 Bytes liest, gibt, warum gab es dann im ersten Fall keine Auffüllung?

Antwort

10

Die Auffüllung wird im zweiten Fall hinzugefügt, da auf Ihrer Maschine ein int auf 4 Byte ausgerichtet ist. So hat es an einer Adresse befinden, der teilbar ist zu 4.

0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 

    a  b  b  b  b  

Wenn keine Polsterung hinzugefügt wird, die int Mitglied beginnt bei Adresse 0x05, was falsch ist. Mit 3 Paddingbytes hinzugefügt:

Jetzt
0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 

    a |  padding  | b  b  b  b 

die int ist bei 0x08, was in Ordnung ist.

+0

I <3 ASCII ART! –

+0

Hi, Dann wie wäre es mit der case struct {int b; Zeichen a; } X; Hier, wenn wir int betrachten, um von der Speicherstelle in mehreren von 4 und Char zu Stat später zu starten. Die Polsterung erfolgt auch in diesem Fall. Warum ist hier ein Padding erforderlich, wenn alle Datenmember den Randbedingungen folgen? – Laavaa

+1

@AbhishekSrinath wegen Arrays. Wenn Sie 'X x [2]' haben, muss das zweite Element - 'x [1]' - auf 4 Bytes ausgerichtet werden, da sein erstes Mitglied ein 'int' ist, das auf 4 Bytes ausgerichtet werden muss. –

3

Es ist nicht nur Effizienz.

Das Problem ist nicht die Größe des Zugriffs per se, aber es ist die Ausrichtung. Auf die meisten Maschinen wird falsch ausgerichtet Zugriff auf Daten verursachen, das Programm zu Absturz und auf typische Maschinen heute ein int eine Adresse ausgerichtet auf einer Vier-Byte-Grenze erfordern: Zugriff auf ein int, deren Adresse nicht auf einer Vier-Byte-Grenze ausgerichtet wird entweder das Programm erheblich verlangsamen, oder es zum Absturz bringen. Ihre erste Struktur enthielt keine Daten mit Ausrichtung Überlegungen, so dass keine Auffüllung erforderlich war. Ihre Sekunde hat eine int, und der Compiler muss sicherstellen, dass bei einem Array von ihnen alle int korrekt ausgerichtet werden. Dies bedeutet , dass 1) die Gesamtgröße der Struktur muss ein Vielfaches von vier sein, und 2) der Offset der int in der Struktur muss ein Vielfaches von vier sein. (unter Berücksichtigung der ersten Anforderung:

struct S 
{ 
    char a; 
    int b; 
    char c; 
}; 

haben im allgemeinen eine Größe von 12, mit einer Polsterung nach beiden char.

)

In anderem langauges, es häufig war die Compiler structs neu zu ordnen, so dass die Elemente mit den strengsten Ausrichtungsanforderungen kamen erste — für struct S, oben, würde dies in geführt hat:

struct S 
{ 
    int b; 
    char a; 
    char c; 
}; 

und eine Größe von 8 statt 12. Sowohl C als auch C++ verbieten dies jedoch.

+0

Hi, Dann wie wäre es mit der case struct {int b; Zeichen a; } X; Hier, wenn wir int betrachten, um von der Speicherstelle in mehreren von 4 und Char zu Stat später zu starten. Die Polsterung erfolgt auch in diesem Fall. Warum ist hier ein Padding erforderlich, wenn alle Datenmember den Randbedingungen folgen? – Laavaa

+0

@AbhishekSrinath Damit wird das nächste Mitglied in einem Array korrekt ausgerichtet. –

0

Das Auffüllen wird durchgeführt, um bestimmte Datentypen auszurichten, d. H. Sicherzustellen, dass Daten eines bestimmten Typs eine Adresse haben, die ein Vielfaches einer bestimmten Zahl ist. Dies variiert zwischen verschiedenen CPU-Modellen, aber oft werden 2-Byte-Ganzzahlen auf Adressen ausgerichtet, die Vielfache von 2 und 4-Byte-Ganzzahlen zu Adressen sind, die Vielfache von 4 sind. Zeichen müssen normalerweise nicht ausgerichtet werden.

Wenn also nur ein Feld in einer Struktur vorhanden ist, dann ist, solange die Struktur an einer Adresse mit der richtigen Grenze platziert ist, keine Auffüllung erforderlich. Und es wird immer so sein: Das System richtet Blöcke immer an der größten Grenze aus, die jemals benötigt wird, normalerweise 4 Bytes oder 8 Bytes. Die eine Sache in der Struktur wird an einer richtigen Grenze sein. Das Problem tritt nur auf, wenn Sie mehrere Felder haben, da dann die Länge eines Felds nicht dazu führt, dass das nächste Feld an der richtigen Grenze ist. In Ihrem Beispiel haben Sie also ein char, das natürlich 1 Byte benötigt, und ein int, das 4 annimmt. Nehmen wir an, die Struktur befindet sich an der Adresse 0x1000. Ohne Character würde das Zeichen dann auf 0x1000 und das Int auf 0x1001 gesetzt. Int-Werte sind jedoch effizienter, wenn sie an 4-Byte-Grenzen liegen. Daher fügt der Compiler einige Pad-Bytes hinzu, um ihn zur nächsten solchen Grenze, 0x1004, zu verschieben. So, jetzt haben Sie char (1 Byte), Padding (3 Bytes), int (4 Bytes), insgesamt 8 Bytes.

Es gibt nichts, was Sie tun können, um die Situation in diesem Fall zu verbessern. Jede Struktur wird auf eine 4- oder 8-Byte-Grenze ausgerichtet, wenn also das Minimum 5 Bytes beträgt, wird dies in der Praxis immer auf mindestens 8 aufgerundet. (Der sizeof zeigt den Abstand zwischen Structs nur innerhalb, aber der Speicher ist immer noch verloren.)

In anderen Fällen können Sie die Anzahl der zusätzlichen Pad Bytes minimieren, indem Sie die Reihenfolge der Felder neu anordnen. Wie gesagt, du hattest drei Chars und drei Int's. Wenn Sie die Struktur als

struct {char a; int b; char c; int d; char e; int f;} 

dann der Compiler erklären wird 3 Byte nach dem ersten Zeichen fügen Sie die erste int auszurichten, und dann drei weitere Bytes nach dem zweiten Zeichen des zweiten int auszurichten. Das ergibt char (1) + pad (3) + int (4) + char (1) + pad (3) + int (4) + char (1) + pad (3) + int (4) = 24.

Aber wenn Sie stattdessen es erklärt:

struct {char a; char c; char e; int b; int d; int f;} 

dann würden Sie char (1) + char (1) + char (1) + Pad (1) + int (4) + int (4 erhalten) + int (4) = 16.

Vor Jahren habe ich den Rat gelesen, immer zuerst die größten Elemente zu setzen, um die Polsterung zu minimieren, dh erst Longs, dann Ints, dann Shorts und dann Chars.

Wenn Sie Tausende oder Millionen davon zuweisen, können Sie mit dieser Technik viel Speicher sparen. Wenn Sie nur ein oder zwei zuweisen, wird es nicht viel ausmachen.

+0

Hallo, Dann wie wäre es mit der Fallstruktur { int b; Zeichen a; } X; Hier, wenn wir int betrachten, um von der Speicherstelle in mehreren von 4 und Char zu Stat später zu starten. Die Polsterung erfolgt auch in diesem Fall. Warum ist hier ein Padding erforderlich, wenn alle Datenmember den Randbedingungen folgen? – Laavaa

+0

@AbhishekSrinath Wenn Sie eine Größe davon machen, denke ich, dass Sie 5, keinen Hinweis auf eine Polsterung bekommen werden. Aber wenn Sie solche Objekte wirklich erstellen, richtet der Heap jedes Objekt an der Worst-Case-Grenze aus, entweder 4 oder 8, so dass Sie am Anfang des nächsten Objekts sowieso 3 Byte mehr haben. Es kann davon abhängen, ob Sie einzelne Objekte aus dem Heap, Objekten auf dem Stapel oder Arrays zuweisen. Ich bin mir ziemlich sicher, dass das Auffüllen alle implementierungsabhängig ist, sodass Sie auf verschiedenen Systemen unterschiedliche Ergebnisse erhalten. Der Punkt ist, die Anforderungen der CPU für die Datenausrichtung zu erfüllen. – Jay

0

Padding ist das Konzept der alignment, für die issue of computer efficiency and the speed of the access of the data, ausgerichtet sind, Daten perfekt mit den fetching cycle of the processor from the addresses where the data are stored, it doesn't mean that with out alignment processor doesn't work it only meant for the speed access of the memory zugegriffen wird, für den Integer-Datentyp es ist 4 Byte-Ausrichtung durch den Compiler durchgeführt wird, um die Daten effizienter durch den Prozessor zugreifen .(im 32-Bit-System)

Im Falle von char nur ein Byte nur von den Daten benötigt, so dass keine Ausrichtung erforderlich ist, da jedes Byte selbst verfügbar ist (in RAM there are pages and each page size is 1 byte), aber für Integer benötigen wir 4 Byte und kein 4 Byte ist verfügbar oder es wird nichts als Zugriff auf 4 Byte gleichzeitig bezeichnet, also macht der Compiler eine Ausrichtungsregel, bei der die ganzzahligen Daten in den richtigen Adressen sind.

und durch die es schneller Speicherzugriff auf die Daten wird.

+0

Warum setzen Sie Wörter willkürlich in Code/Vor-Tags? Hast du vergessen, deine Quellen zu benennen? –

Verwandte Themen