( Jawaban di atas menjelaskan alasannya dengan cukup jelas, tetapi tampaknya tidak sepenuhnya jelas tentang ukuran bantalan, jadi, saya akan menambahkan jawaban sesuai dengan apa yang saya pelajari dari The Lost Art of Structure Packing , telah berevolusi menjadi tidak terbatas pada C
, tetapi juga berlaku untuk Go
, Rust
. )
Perataan memori (untuk struct)
Aturan:
- Sebelum setiap anggota individu, akan ada padding sehingga untuk membuatnya mulai dari alamat yang dapat dibagi berdasarkan ukurannya.
misalnya pada sistem 64 bit, int
harus dimulai pada alamat yang dapat dibagi dengan 4, dan long
oleh 8, short
dengan 2.
char
dan char[]
istimewa, bisa berupa alamat memori apa pun, sehingga tidak perlu diisi sebelumnya.
- Sebab
struct
, selain kebutuhan pelurusan untuk setiap anggota individu, ukuran seluruh struct itu sendiri akan disejajarkan dengan ukuran yang dapat dibagi berdasarkan ukuran anggota individu terbesar, dengan melapisi bagian ujungnya.
misalnya jika anggota struct terbesar adalahlong
kemudian dapat dibagi 8, int
kemudian oleh 4, short
kemudian oleh 2.
Urutan anggota:
- Urutan anggota mungkin mempengaruhi ukuran struct yang sebenarnya, jadi ingatlah itu. misalnya
stu_c
dan stu_d
dari contoh di bawah ini memiliki anggota yang sama, tetapi dalam urutan yang berbeda, dan menghasilkan ukuran yang berbeda untuk 2 struct.
Alamat dalam memori (untuk struct)
Aturan:
- Sistem 64 bit
alamat Struct dimulai dari (n * 16)
byte. ( Anda dapat melihat pada contoh di bawah ini, semua alamat hex yang dicetak dari structs berakhir dengan 0
. )
Alasan : anggota struct individu terbesar yang mungkin adalah 16 byte (long double
).
- (Pembaruan) Jika sebuah struct hanya berisi anggota
char
sebagai, alamatnya dapat dimulai dari alamat mana pun.
Ruang kosong :
- Ruang kosong antara 2 struct dapat digunakan oleh variabel non-struct yang bisa masuk.
Misalnya di test_struct_address()
bawah, variabel x
berada di antara struct yang berdekatan g
dan h
.
Tidak peduli apakah x
dinyatakan, h
alamat tidak akan berubah, x
cukup gunakan kembali ruang kosong yang g
terbuang.
Kasus serupa untuk y
.
Contoh
( untuk sistem 64 bit )
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;
}
Hasil eksekusi - 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
Hasil eksekusi - 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
Dengan demikian alamat mulai untuk setiap variabel adalah g: d0 x: dc h: e0 y: e8