Bee*_*ope 25 c struct pointers language-lawyer c11
考虑以下结构:
struct s {
int a, b;
};
Run Code Online (Sandbox Code Playgroud)
通常为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);
Run Code Online (Sandbox Code Playgroud)
这个程序的未定义行为有什么问题吗?如果是这样,它在哪里变得未定义?如果不是UB,是否保证始终打印以下内容:
o2.a=3
o2.b=4
o1.a=1
o1.b=3
Run Code Online (Sandbox Code Playgroud)
特别是,我想知道o1when指向的对象发生了什么o2,它与它重叠,被写入。是否仍然允许访问未破坏的部分 ( o1->a)?访问被破坏的部分是否与访问o1->b相同o2->a?
有效类型在这里如何应用?当您谈论非重叠对象和指向与最后一个存储相同位置的指针时,规则就足够清楚了,但是当您开始谈论对象或重叠对象部分的有效类型时,规则就不太清楚了。
如果第二次写入的类型不同,会有什么变化吗?如果成员是 say intandshort而不是两个ints?
如果你想在那里玩,这里有一个神马。
1这个答案也适用于不是这种情况的平台:例如,有些可能有大小 4 和对齐方式 2。在大小和对齐方式相同的平台上,这个问题不适用,因为对齐、重叠的对象会不可能,但我不确定是否有这样的平台。
M.M*_*M.M 15
基本上这是标准中的所有灰色区域;严格的别名规则指定了基本情况,让读者(和编译器供应商)填写细节。
一直在努力编写更好的规则,但到目前为止还没有产生任何规范文本,我不确定 C2x 的状态如何。
正如我在对您上一个问题的回答中所述,最常见的解释是p->qmean(*p).q和有效类型适用于所有*p,即使我们随后继续 apply .q。
在这种解释下,printf("o1.a=%d\n", o1->a);会导致未定义的行为,因为该位置的有效类型*o1不是s(因为它的一部分已被覆盖)。
这种解释的基本原理可以在如下函数中看到:
void f(s* s1, s* s2)
{
s2->a = 5;
s1->b = 6;
printf("%d\n", s2->a);
}
Run Code Online (Sandbox Code Playgroud)
通过这种解释,最后一行可以优化为puts("5");,但如果没有它,编译器将不得不考虑函数调用可能已经存在f(o1, o2);,因此失去了据称由严格别名规则提供的所有好处。
类似的论点适用于两个不相关的结构类型,它们碰巧int在不同的偏移处有一个成员。