Розглянемо таку структуру:
struct s {
int a, b;
};
Зазвичай 1 , ця структура матиме розмір 8 та вирівнювання 4.
Що робити, якщо ми створимо два struct s
об'єкти (точніше, запишемо у виділене сховище два такі об’єкти), причому другий об’єкт перекриє перший?
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);
Чи є щось щодо цієї програми невизначеною поведінкою? Якщо так, то де це стає невизначеним? Якщо це не UB, чи гарантовано завжди друкувати наступне:
o2.a=3
o2.b=4
o1.a=1
o1.b=3
Зокрема, я хочу знати, що відбувається з об'єктом, на який вказує, o1
коли o2
, що перекриває його, написано. Чи все ж дозволено отримувати доступ до незаблокованої частини ( o1->a
)? Чи доступ до дозвоненої частини o1->b
просто такий самий, як і доступ o2->a
?
Як тут застосовується ефективний тип ? Правила є досить чіткими, коли ви говорите про неперекриваються об'єкти та покажчики, які вказують на те саме місце, що і останнє сховище, але коли ви починаєте говорити про ефективний тип частин об'єктів або об'єктів, що перекриваються, менш зрозуміло.
Чи змінилось би щось, якби друге письмо було іншого типу? Якщо члени кажуть , int
і short
замість двох int
років?
Ось богбол, якщо ви хочете пограти з ним там.
1 Ця відповідь стосується платформ, де це теж не так: наприклад, деякі можуть мати розмір 4 та вирівнювання 2. На платформі, де розмір та вирівнювання були однаковими, це питання не застосовуватиметься, оскільки об'єкти, що перекриваються, вирівнюються бути неможливим, але я не впевнений, чи є така платформа.