考虑以下结构:
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
S'
如果您想在这里玩,这里有一个螺栓。
1此答案适用于并非如此的平台:例如,某些平台的尺寸和对齐方式可能为4。在尺寸和对齐方式相同的平台上,此问题将不适用,因为对齐的重叠对象会不可能,但是我不确定是否有这样的平台。