( Yukarıdaki cevaplar nedeni oldukça açık bir şekilde açıkladı, ancak dolgu boyutu hakkında tamamen net görünmüyor, bu yüzden Yapının Kayıp Sanatı Ambalajından öğrendiklerime bir cevap ekleyeceğim C
, ancak bununla sınırlı kalmamak için gelişti , ancak Aynı işlem Go
, Rust
. )
Bellek hizalama (yapı için)
Kurallar:
- Her bir üyeden önce, boyutuna göre bölünebilen bir adreste başlamasını sağlamak için dolgu olacaktır.
örneğin 64 bit sistemde, int
4 ve long
8 short
ile 2'ye bölünebilen adreste başlamalıdır .
char
ve char[]
özeldir, herhangi bir bellek adresi olabilir, bu yüzden onlardan önce dolguya ihtiyaç duymazlar.
- Çünkü
struct
, her bir üye için hizalama ihtiyacı dışında, tüm yapının büyüklüğü, en büyük bireysel üye boyutuna göre bölünebilir bir boyuta, sonunda dolgu ile hizalanacaktır.
örneğin, yapıların en büyük üyesi long
8, int
sonra 4, short
sonra 2 ile bölünebilirse .
Üye sırası:
- Üyenin sırası yapının gerçek boyutunu etkileyebilir, bu yüzden bunu aklınızda bulundurun. örneğin
stu_c
ve stu_d
aşağıdaki örnekte aynı üyeler vardır, ancak farklı sırayla ve 2 yapı için farklı boyutlarda sonuçlanır.
Bellekteki adres (yapı için)
Kurallar:
- 64 bit sistem
Yapı adresi (n * 16)
bayttan başlar . ( Aşağıdaki örnekte, yapıların tüm basılı onaltılık adresleri ile biter 0
. )
Sebep : olası en büyük bireysel yapı üyesi 16 bayttır ( long double
).
- (Güncelleme) Bir yapı yalnızca
char
üye olarakiçeriyorsa, adresi herhangi bir adreste başlayabilir.
Boş alan :
- 2 yapı arasındaki boş alan, sığabilecek yapısal olmayan değişkenler tarafından kullanılabilir.
Örneğin test_struct_address()
aşağıda değişken, x
bitişik yapı g
ve arasında bulunur h
. Beyan
edilip edilmediğine bakılmaksızın x
, h
adresi değişmez, x
sadece g
boşa giden boş alanı tekrar kullanır .
İçin benzer durum y
.
Misal
( 64 bit sistem için )
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;
}
Yürütme sonucu - 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
Yürütme sonucu - 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
Böylece her değişken için adres başlangıcı g: d0 x: dc h: e0 y: e8