Rozważ następującą strukturę:
struct s {
int a, b;
};
Zazwyczaj 1 , ta struktura będzie miała rozmiar 8 i wyrównanie 4.
Co jeśli utworzymy dwa struct sobiekty (a ściślej zapisujemy do przydzielonej pamięci dwa takie obiekty), przy czym drugi obiekt nakłada się na pierwszy?
char *storage = malloc(3 * sizeof(struct s));
struct s *o1 = (struct s *)storage; // offset 0
struct s *o2 = (struct s *)(storage + alignof(struct s)); // offset 4
// now, o2 points half way into o1
*o1 = (struct s){1, 2};
*o2 = (struct s){3, 4};
printf("o2.a=%d\n", o2->a);
printf("o2.b=%d\n", o2->b);
printf("o1.a=%d\n", o1->a);
printf("o1.b=%d\n", o1->b);
Czy coś w tym programie jest niezdefiniowane? Jeśli tak, to gdzie staje się niezdefiniowane? Jeśli nie jest to UB, to zawsze gwarantuje wydruk następujących informacji:
o2.a=3
o2.b=4
o1.a=1
o1.b=3
W szczególności chcę wiedzieć, co dzieje się z obiektem wskazywanym przez o1moment o2, w którym nakłada się on na siebie. Czy nadal można uzyskiwać dostęp do niezakleszczonej części ( o1->a)? Czy dostęp do części zablokowanej jest o1->bpo prostu taki sam jak dostęp o2->a?
W jaki sposób stosuje się tutaj typ skuteczny ? Reguły są wystarczająco jasne, gdy mówimy o nie nakładających się obiektach i wskaźnikach, które wskazują na to samo miejsce co ostatni sklep, ale kiedy zaczynasz mówić o efektywnym typie części obiektów lub nakładających się obiektów, jest to mniej jasne.
Czy cokolwiek by się zmieniło, gdyby drugi zapis był innego typu? Jeżeli członkowie byli powiedzieć, inta shortraczej niż dwa ints?
Oto godbolt, jeśli chcesz się z nim pobawić.
1 Ta odpowiedź dotyczy również platform, na których tak nie jest: np. Niektóre mogą mieć rozmiar 4 i wyrównanie 2. Na platformie, w której rozmiar i wyrównanie były takie same, pytanie nie miałoby zastosowania, ponieważ wyrównane, nakładające się obiekty być niemożliwe, ale nie jestem pewien, czy istnieje taka platforma.