( 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ür Go
, Rust
. )
Memory Align (für Struktur)
Regeln:
- Vor jedem einzelnen Mitglied wird ein Auffüllen vorgenommen, damit es an einer Adresse beginnt, die durch ihre Größe teilbar ist.
Beispiel: Auf einem 64-Bit-System int
sollte an einer Adresse beginnen, die durch 4 und long
durch 8 short
durch 2 teilbar ist .
char
und char[]
sind speziell, könnte jede Speicheradresse sein, so dass sie nicht vor ihnen aufgefüllt werden müssen.
- Denn
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:
- Die Reihenfolge der Mitglieder kann sich auf die tatsächliche Größe der Struktur auswirken. Beachten Sie dies. zB haben das
stu_c
und stu_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:
- 64-Bit-Systemstrukturadresse
beginnt bei (n * 16)
Bytes. ( Im folgenden Beispiel sehen Sie, dass alle gedruckten Hex-Adressen von Strukturen mit enden 0
. )
Grund : Das möglicherweise größte einzelne Strukturelement ist 16 Byte ( long double
).
- (Update) Wenn eine Struktur nur ein
char
Mitgliedenthält, kann ihre Adresse an einer beliebigen Adresse beginnen.
Leerer Raum :
- Der leere Raum zwischen 2 structs konnte durch nicht-struct Variablen verwendet werden , die in passen könnte.
B. in test_struct_address()
folgenden werden die variablen x
befindet sich zwischen benachbarten struct g
und h
.
Unabhängig davon, ob x
deklariert h
wird, ändert sich die Adresse nicht. Verwenden Sie x
einfach den leeren Speicherplatz, der g
verschwendet wurde.
Ähnliches gilt für y
.
Beispiel
( für 64-Bit-System )
memory_align.c :
/**
* Memory align & padding - for struct.
* compile: gcc memory_align.c
* execute: ./a.out
*/
#include <stdio.h>
// size is 8, 4 + 1, then round to multiple of 4 (int's size),
struct stu_a {
int i;
char c;
};
// size is 16, 8 + 1, then round to multiple of 8 (long's size),
struct stu_b {
long l;
char c;
};
// size is 24, l need padding by 4 before it, then round to multiple of 8 (long's size),
struct stu_c {
int i;
long l;
char c;
};
// size is 16, 8 + 4 + 1, then round to multiple of 8 (long's size),
struct stu_d {
long l;
int i;
char c;
};
// size is 16, 8 + 4 + 1, then round to multiple of 8 (double's size),
struct stu_e {
double d;
int i;
char c;
};
// size is 24, d need align to 8, then round to multiple of 8 (double's size),
struct stu_f {
int i;
double d;
char c;
};
// size is 4,
struct stu_g {
int i;
};
// size is 8,
struct stu_h {
long l;
};
// test - padding within a single struct,
int test_struct_padding() {
printf("%s: %ld\n", "stu_a", sizeof(struct stu_a));
printf("%s: %ld\n", "stu_b", sizeof(struct stu_b));
printf("%s: %ld\n", "stu_c", sizeof(struct stu_c));
printf("%s: %ld\n", "stu_d", sizeof(struct stu_d));
printf("%s: %ld\n", "stu_e", sizeof(struct stu_e));
printf("%s: %ld\n", "stu_f", sizeof(struct stu_f));
printf("%s: %ld\n", "stu_g", sizeof(struct stu_g));
printf("%s: %ld\n", "stu_h", sizeof(struct stu_h));
return 0;
}
// test - address of struct,
int test_struct_address() {
printf("%s: %ld\n", "stu_g", sizeof(struct stu_g));
printf("%s: %ld\n", "stu_h", sizeof(struct stu_h));
printf("%s: %ld\n", "stu_f", sizeof(struct stu_f));
struct stu_g g;
struct stu_h h;
struct stu_f f1;
struct stu_f f2;
int x = 1;
long y = 1;
printf("address of %s: %p\n", "g", &g);
printf("address of %s: %p\n", "h", &h);
printf("address of %s: %p\n", "f1", &f1);
printf("address of %s: %p\n", "f2", &f2);
printf("address of %s: %p\n", "x", &x);
printf("address of %s: %p\n", "y", &y);
// g is only 4 bytes itself, but distance to next struct is 16 bytes(on 64 bit system) or 8 bytes(on 32 bit system),
printf("space between %s and %s: %ld\n", "g", "h", (long)(&h) - (long)(&g));
// h is only 8 bytes itself, but distance to next struct is 16 bytes(on 64 bit system) or 8 bytes(on 32 bit system),
printf("space between %s and %s: %ld\n", "h", "f1", (long)(&f1) - (long)(&h));
// f1 is only 24 bytes itself, but distance to next struct is 32 bytes(on 64 bit system) or 24 bytes(on 32 bit system),
printf("space between %s and %s: %ld\n", "f1", "f2", (long)(&f2) - (long)(&f1));
// x is not a struct, and it reuse those empty space between struts, which exists due to padding, e.g between g & h,
printf("space between %s and %s: %ld\n", "x", "f2", (long)(&x) - (long)(&f2));
printf("space between %s and %s: %ld\n", "g", "x", (long)(&x) - (long)(&g));
// y is not a struct, and it reuse those empty space between struts, which exists due to padding, e.g between h & f1,
printf("space between %s and %s: %ld\n", "x", "y", (long)(&y) - (long)(&x));
printf("space between %s and %s: %ld\n", "h", "y", (long)(&y) - (long)(&h));
return 0;
}
int main(int argc, char * argv[]) {
test_struct_padding();
// test_struct_address();
return 0;
}
Ausführungsergebnis - test_struct_padding()
:
stu_a: 8
stu_b: 16
stu_c: 24
stu_d: 16
stu_e: 16
stu_f: 24
stu_g: 4
stu_h: 8
Ausführungsergebnis - test_struct_address()
:
stu_g: 4
stu_h: 8
stu_f: 24
address of g: 0x7fffd63a95d0 // struct variable - address dividable by 16,
address of h: 0x7fffd63a95e0 // struct variable - address dividable by 16,
address of f1: 0x7fffd63a95f0 // struct variable - address dividable by 16,
address of f2: 0x7fffd63a9610 // struct variable - address dividable by 16,
address of x: 0x7fffd63a95dc // non-struct variable - resides within the empty space between struct variable g & h.
address of y: 0x7fffd63a95e8 // non-struct variable - resides within the empty space between struct variable h & f1.
space between g and h: 16
space between h and f1: 16
space between f1 and f2: 32
space between x and f2: -52
space between g and x: 12
space between x and y: 12
space between h and y: 8
Somit ist der Adressstart für jede Variable g: d0 x: dc h: e0 y: e8