Розглянемо таку структуру:
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. На платформі, де розмір та вирівнювання були однаковими, це питання не застосовуватиметься, оскільки об'єкти, що перекриваються, вирівнюються бути неможливим, але я не впевнений, чи є така платформа.