使用 union 在 C 中输入双关语

Type punning in C using union

考虑以下代码:

union u{
    int i;
    long j[2];
};

int main(void){
    union u *u = malloc(sizeof *u);
    u->i = 10;
    printf("%li\n", u->j[0]);
}

我想用6.5解释代码的合法性:

An object shall have its stored value accessed only by an lvalue expression that has one of the following types:

— a type compatible with the effective type of the object,

[...]

— an aggregate or union type that includes one of the aforementioned types among its members (including, recursively, a member of a subaggregate or contained union), or

将此应用于上面的示例我们有:

  1. u->i = 10; 使 u->i 对象具有有效类型 int
  2. 左值 u 有一个 union 类型,其中包含类型 int.
  3. 的成员
  4. 具有未指定值的对象 u->j[0] 使用具有类型 int.
  5. 成员的 union u 类型的左值 u 进行访问
  6. 应用引用 6.5 我们知道这里没有 UB。

问题:这样的推理是否正确?或者它有什么错误?

是的,你的推理是正确的。这不是未定义的行为,而是根据 C11 第 6.2.6.1/7 节的未指定行为:

When a value is stored in a member of an object of union type, the bytes of the object representation that do not correspond to that member but do correspond to other members take unspecified values.

第 3.19.3 节阐明了这意味着什么:

unspecified value: valid value of the relevant type where this International Standard imposes no requirements on which value is chosen in any instance

附件 J:可移植性问题

中提醒了这一点

J.1 Unspecified behavior
1 The following are unspecified:
— ...
— The value of padding bytes when storing values in structures or unions (6.2.6.1).
— The values of bytes that correspond to union members other than the one last stored into (6.2.6.1).
— ...

J2 中未指定任何有关访问联合成员的内容,这是关于未定义行为的

话虽这么说,可移植性问题可能会很严重,如第 6.2.6.1/6 节提醒的那样:

The value of a structure or union object is never a trap representation, even though the value of a member of the structure or union object may be a trap representation.

陷阱表示是“不需要表示对象类型值的对象表示”(定义),理解为“获取陷阱表示 可能会执行陷阱 但不需要 ”(脚注)。所以访问 inactive 值可能会导致程序中断,但如果没有,那只是没有保证。