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

在C中,通过联合指针进行类型双关合法吗?,c,language-lawyer,type-punning,C,Language Lawyer,Type Punning,这个问题的灵感来源于,复制如下,它通过指针进行非法类型双关语: # include <stdio.h> int main() { char p[]={0x01,0x02,0x03,0x04}; int *q = p; printf("%x",*q); return 0; } #包括 int main() { 字符p[]={0x01,0x02,0x03,0x04}; int*q=p; printf(“%x”,*q); 返回0; } 我的问题是,上述

这个问题的灵感来源于,复制如下,它通过指针进行非法类型双关语:

# include <stdio.h>
int main()
{
    char p[]={0x01,0x02,0x03,0x04};
    int *q = p;
    printf("%x",*q);
    return 0;
}
#包括
int main()
{
字符p[]={0x01,0x02,0x03,0x04};
int*q=p;
printf(“%x”,*q);
返回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;
}
#包括
#包括
联合字符集{
charp[4];
int32_t q;
};
int main()
{
字符p[]={0x01,0x02,0x03,0x04};
int*q=&((union char_int*)p)->q;
printf(“%x”,*q);
返回0;
}

相关的,我相信这些字节将为标准允许的所有可能的表示形式形成一个合法的
int32\t
值,但是如果有人能确认这个额外的细节,那也太好了。

的意思是“一个对象的存储值只能由具有以下类型之一的左值表达式访问…”取决于如何定义该规则中使用的“对象”和“由”。据我所知,除了标准的作者可能期望实现能够明智地解释规则这一事实之外,在这些词的含义上从来没有类似的共识。请注意,根据规则的字面解释,类似于:

short volatile x;
int test(void)
{
  int y = x+1;
  return y;
}
将调用UB,因为y的生存期从代码进入
test
时开始,而这又发生在读取
x
之前,但在读取
x
之前,它无法接收值。因此,
y
的值必须在其生存期内更改,但此类操作不涉及任何类型为
int
的左值表达式或任何其他允许的类型


显然,这样的解释将是荒谬的,但一个规则,它忽略了简单的情况下,假定执行将知道要做什么,不能依赖于考虑更复杂的。关于所讨论的构造,一些编译器会说,在左值表达式中,如
someUnion.member=23
中,union对象“被”左值表达式
someUnion
修改,但不一定允许成员类型的左值或包含相同成员的其他union类型的左值在其他地方访问此类对象。但是,如果不清楚“by”一词的含义,就不可能将任何特定解释定性为正确或错误。

由于C 2018 6.3.2.3 7,C标准一般不定义
(union char_int*)p
的行为:“指向对象类型的指针可能会转换为指向不同对象类型的指针。如果结果指针未正确对齐引用类型,则行为未定义…”如果
p
恰好按照
union char\u int
的需要对齐,则标准会说“当再次转换回来时,结果应与原始指针相等。”标准没有规定此指针实际上有任何值以任何其他方式充当
union char\u int*
。换句话说,如果我们有
union char\u int*x=(union char\u int*)p;
,这是成功的,因为对齐正好起作用,标准除了
(char*)之外,没有提到
x
的值x
产生的东西与
p
相当。
x
的值不一定是一个有效地址,否则-
*x
可能引用与
p
完全不同的内存。这实际上不是一个合法或非法的问题,而是一个未定义的行为。第一个是导致未定义的行为由于违反严格别名而导致viour。两者都会导致未定义的行为,因为
*q
的值受到实现的基本整数表示的影响(主要是endianness,但平台可能不使用2s补码)如上所述,由于对齐,两者都未定义。@Graeme:endianness引起的变化是实现定义的,而不是未定义的。标准要求实现记录其内存表示,见C 2018 6.2.6.1 2:除位字段外,对象由一个或多个字节的连续序列组成,其数量、顺序和编码是显式指定的或实现定义的指针转换问题之后,问题出在别名上,而不是表示方式。@EricPostphil相关,我是在想象,还是有某种语言将结构的地址强制转换为它的第一个元素类型的地址?当然这里我们有
union
,我们也不是从它的地址强制转换,所以说与这种情况无关。严格的别名规则是严格向前的,在表达式
int y=x+1;
中没有严格的别名冲突,因为对象
y
的存储值不是由规则不允许的类型访问的。关于生存期以及变量开始生存期的时间和分配时间的讨论是您自己的解释,标准没有说它们相关,我也不明白你的例子是如何的UB。你的解释似乎迫使生命周期和严格的别名之间存在一种不存在的联系,但是如果你能添加一些,我会很高兴学到一些新的东西explanation@user2162550当前位置书面规则不仅仅禁止其他人的左撇子访问r类型,但不是正确类型的左值。正确的修复方法是将规则限制为以前在与左值访问相同的上下文中访问过的对象,并要求用于访问的左值与该上下文中的早期对象明显关联。当执行类似
的表达式时