【发布时间】:2014-01-17 00:44:01
【问题描述】:
引用自 C99 标准:
6.5.2.3
5 一个特殊的保证是为了简化联合的使用:如果联合包含多个共享相同初始序列的结构(见下文),并且如果联合对象当前包含这些结构之一,允许在任何可见联合的完整类型声明的任何地方检查其中任何一个的公共初始部分。如果相应的成员具有兼容的类型,则两个结构共享一个公共初始序列(并且,对于 bit-字段,宽度相同)用于一个或多个初始成员的序列。
有这个案例的例子:
// The following code is not a valid fragment because
// the union type is not visible within the function f.
struct t1 { int m; };
struct t2 { int m; };
int f(struct t1 *p1, struct t2 *p2)
{
if (p1->m < 0)
p2->m = -p2->m;
return p1->m;
}
int g()
{
union
{
struct t1 s1;
struct t2 s2;
} u;
/* ... */
return f(&u.s1, &u.s2);
}
我添加了一些更改:
#include <stdio.h>
struct t1 { int m; };
struct t2 { int m; };
union u
{
struct t1 s1;
struct t2 s2;
};
int foo(struct t1 *p1, struct t2 *p2)
{
if (p1->m)
p2->m = 2;
return p1->m;
}
int main(void)
{
union u u;
u.s1.m = 1;
printf("%d\n", foo(&u.s1, &u.s2));
}
如您所见,我已将联合声明移到外部,以便在 foo() 中可见。根据标准的评论,这应该使我的代码正确,但看起来严格的别名仍然会破坏 clang 3.4 和 gcc 4.8.2 的代码。
使用 -O0 输出:
2
-O2 的输出:
1
对于两个编译器。
所以我的问题是:
C 真的依赖联合声明来决定某些结构是否是严格别名规则的例外吗?还是 gcc/clang 都有 bug?
这对我来说似乎真的很糟糕,因为即使函数和联合都在同一个标头中声明,这并不能保证联合在带有函数主体的翻译单元中可见。
【问题讨论】:
-
使用 gcc 4.4.7 输出 2
-
在另一个线程中检查我的未答复,尤其是 GCC 邮件列表讨论的链接:stackoverflow.com/a/19807355/1546653 我也非常希望看到这一点得到澄清。
-
您首先给出的示例:是否超出标准?它看起来不像标准所说的示例?我认为标准说如果你在“main”中做,“u.s1.m = 5”,那么编译器必须假设“u.s2.m”已经改变;但如果你传递指向“u.s1”和“u.s2”的指针,那就完全不同了。
-
标准语言清晰;联合声明中存在两个结构应被视为通知编译器代码将覆盖这两种类型,因此公共初始序列的成员可能会别名。 gcc 的作者不喜欢标准所说的,并选择忽略它,但我可以想象标准没有其他理由提到 complete 类型如果这种可见性被认为不够充分,则可见,请注意可能出现混叠。
标签: c struct unions pointer-aliasing