引用 C99 标准:
6.5.2.3
5 为了简化联合的使用,我们做了一个特殊的保证:如果一个联合包含多个共享一个共同初始序列的结构(见下文),并且如果联合对象当前包含这些结构之一,则允许检查它们中的任何一个的公共初始部分在任何地方都可以看到完整类型的联合声明。如果对应的成员对于一个或多个初始成员的序列具有兼容的类型(并且对于位域,具有相同的宽度),则两个结构共享一个共同的初始序列。
这种情况有一个例子:
// 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 都有错误?
这对我来说似乎真的很糟糕,因为即使函数和联合都在同一个头文件中声明,这并不能保证联合在函数体的翻译单元中是可见的。