【发布时间】:2019-06-28 08:16:54
【问题描述】:
由this question提示:
C11 standard 声明指向联合的指针可以转换为指向其每个成员的指针。来自第 6.7.2.1p17 节:
联合的大小足以容纳最大的 其成员。最多一个成员的值可以是 随时存储在联合对象中。 指向联合的指针 适当转换的对象指向其每个成员(或 如果成员是位域,则指向它所在的单元 驻留),反之亦然。
这意味着您可以执行以下操作:
union u {
int a;
double b;
};
union u myunion;
int *i = (int *)&u;
double *d = (double *)&u;
u.a = 2;
printf("*i=%d\n", *i);
u.b = 3.5;
printf("*d=%f\n", *d);
但是反过来呢:在上述联合的情况下,int * 或double * 可以安全地转换为union u * 吗?考虑以下代码:
#include <stdio.h>
union u {
int a;
double b;
};
void f(int isint, union u *p)
{
if (isint) {
printf("int value=%d\n", p->a);
} else {
printf("double value=%f\n", p->b);
}
}
int main()
{
int a = 3;
double b = 8.25;
f(1, (union u *)&a);
f(0, (union u *)&b);
return 0;
}
在本例中,指向int 和double 的指针,它们都是union u 的成员,被传递给一个需要union u * 的函数。一个标志被传递给函数来告诉它访问哪个“成员”。
假设,如本例,访问的成员与实际传入的对象的类型相匹配,上述代码是否合法?
我在 gcc 6.3.0 上使用 -O0 和 -O3 编译了这个并且都给出了预期的输出:
int value=3
double value=8.250000
【问题讨论】:
-
您甚至不需要别名规则来查看这可能具有标准未定义的行为。如果
double需要八字节对齐,那么联合也需要。但是int a可能只有四字节对齐,在这种情况下将&a转换为union u *的行为没有定义。
标签: c language-lawyer unions strict-aliasing