首页 > 解决方案 > 作为联合成员的类型可以为该联合别名吗?

问题描述

这个问题提示:

C11 标准规定指向联合的指针可以转换为指向其每个成员的指针。从第 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);

但是反过来呢:在上述联合的情况下, aint *double *可以安全地转换为 aunion 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为 a 的函数。union u *一个标志被传递给函数以告诉它要访问哪个“成员”。

假设在这种情况下,访问的成员与实际传入的对象的类型匹配,上面的代码是否合法?

我在 gcc 6.3.0 上编译了这个,-O0并且-O3两者都给出了预期的输出:

int value=3
double value=8.250000

标签: clanguage-lawyerunionsstrict-aliasing

解决方案


在这个例子中,指向 int 和 double 的指针,它们都是 union u 的成员,被传递给一个需要 union u * 的函数。一个标志被传递给函数以告诉它要访问哪个“成员”。

假设在这种情况下,访问的成员与实际传入的对象的类型匹配,上面的代码是否合法?

您似乎将分析的重点放在工会成员类型上的严格别名规则上。然而,鉴于

union a_union {
    int member;
    // ...
} my_union, *my_union_pointer;

,我倾向于争辩说,除了访问成员类型的对象之外,还my_union.member表示my_union_pointer->member访问类型对象的存储值。union a_union因此,如果my_union_pointer实际上并不指向有效类型为的对象,union a_union则确实违反了严格的别名规则——关于类型union a_union——因此行为是未定义的。


推荐阅读