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