我有一个关于严格别名规则,工会和标准的问题 . 假设我们有以下代码:
#include <stdio.h>
union
{
int f1;
short f2;
} u = {0x1};
int * a = &u.f1;
short * b = &u.f2;
int main()
{
u.f1 = 1;
*a += 1;
u.f2 = 2;
*b *= 2;
printf( "%d %hd\n", *a, *b);
return 0;
}
现在让我们看看它是如何工作的:
$ gcc-5.1.0-x86_64 t.c -O3 -Wall && ./a.out
2 4
$ gcc-5.1.0-x86_64 t.c -O3 -Wall -fno-strict-aliasing && ./a.out
4 4
我们可以看到严格别名会破坏依赖关系 . 此外,它似乎是一个正确的代码而不破坏严格别名规则 .
-
结果是否在工会字段的情况下,铺设在该地址的对象与所有类型的工会成员兼容?
-
如果1为真,那么编译器应该如何处理指向union成员的指针?这是标准中的一个问题吗? allows 这样的编译器行为?如果没有 - 为什么?
-
一般来说,编译器使用正确代码的不同行为在任何情况下都是不允许的 . 所以它似乎也是一个编译器错误(特别是如果将地址转换为union字段将在函数内部,SA不会破坏依赖性) .
2 回答
C标准表明明确允许通过联合进行别名化 .
但请检查以下代码:
严格别名规则的目的是假定
a
和b
不是别名 . 但是你可以调用func(&u.f1, &u.f2);
.为了解决这个难题,一个常识性的解决方案是说,工会必须避免严格别名规则的“旁路许可”仅适用于通过名称访问工会成员的时间 .
标准没有明确说明这一点 . 可以认为“如果成员使用......”(6.5.2.3)实际上是指定仅在通过名称访问成员时发生“旁路”,但它并非100%清楚 .
然而,很难提出任何替代和自我一致的解释 . 一种可能的替代解释是,写入
func(&u.f1, &u.f2)
会导致UB,因为重叠的对象被传递给一个函数'knows'它没有收到重叠的对象 - 有点像restrict
违规 .如果我们将第一个解释应用于您的示例,我们会说
printf
中的*a
会导致UB,因为存储在该位置的当前对象是short
,并且6.5.2.3没有启动,因为我们没有使用union成员按名字 .我猜根据你发布的结果,gcc正在使用相同的解释 .
这已在此处讨论过,但我现在找不到该主题 .
C99技术勘误3通过在6.5.2.3节中说明,基于联合方法澄清了类型 - 打孔:
参见1042到1044的here