在 C 中通过联合指针进行类型双关是否合法?

Is type punning via union pointer legal in C?

此题受启发,复制如下,通过指针进行非法类型双关:

# include <stdio.h>
int main()
{
    char p[]={0x01,0x02,0x03,0x04};
    int *q = p;
    printf("%x",*q);
    return 0;
}

我的问题是,以上代码的以下版本是否合法? 我最不确定是否将指向 char 的指针转换为指向包含 char 数组的联合的指针。 这里有很多关于类型双关的问题,但我没有找到涵盖使用指针的重复项这样。

#include <stdio.h>
#include <stdint.h>

union char_int {
    char p[4];
    int32_t q;
};

int main()
{
    char p[]={0x01,0x02,0x03,0x04};
    int *q = &(((union char_int *)p)->q);
    printf("%x",*q);
    return 0;
}

相关,我相信这些字节将形成标准允许的所有可能表示的合法 int32_t 值,但如果有人可以确认这个额外的细节,那就太好了。

"An object shall have its stored value accessed only by an lvalue expression that has one of the following types..." 的含义取决于人们如何定义该规则中使用的词 "object" 和 "by"。据我所知,对于这些词的含义从来没有任何类似的共识,除了标准的作者大概期望实现试图明智地解释规则这一事实之外。请注意,根据规则的字面解释,类似于:

short volatile x;
int test(void)
{
  int y = x+1;
  return y;
}

会调用 UB,因为 y 的生命周期从代码进入 test 时开始,这又发生在 x 被读取之前,但它无法接收值,直到 x 被读取读。因此,y 的值必须在其生命周期内更改,但此类操作不涉及类型 int 的任何左值表达式或任何其他允许的类型。

显然这样的解释是荒谬的,但是不能依赖于假设实现知道该做什么而忽略简单案例的规则来考虑更复杂的案例。关于有问题的构造,一些编译器会说在像 someUnion.member = 23; 这样的左值表达式中,联合对象被修改 "by" 左值表达式 someUnion,但不一定考虑到这样的对象可能会在别处被成员类型的左值访问,也不可能被包含相同成员的其他联合类型的左值访问。然而,在不清楚 "by" 这个词的含义的情况下,实际上不可能将任何特定的解释描述为正确或错误。