我可以对联合成员使用类型双关,联合成员是指向类型的有符号和无符号版本的指针吗?例如,以下
p.u
的用法是否保证按标准工作?
void foo(unsigned *u);
int num = 7;
union
{
int *i;
unsigned *u;
} p;
p.i = #
foo(p.u);
假设
num
是非负的,它似乎在大多数平台上应该没问题。我想知道是否可以保证这两个指针在内存中具有相同的表示形式?
严格来说,不能保证这两种指针类型在内存中具有相同的表示形式。 C 标准仅保证 (6.3.2.3)“指向对象类型的指针可以转换为指向不同对象类型的指针。” /--/ "否则,当再次转换回来时,结果应与 原始指针。”
为了在实践中满足这个要求,
int*
和 unsigned*
在内存中具有相同的表示是极有可能的。到我不会担心的地步。
类型双关本身是明确定义的(6.2.6),就像通过
int
访问有效类型 unsigned int*
的对象,或通过 unsigned int
访问有效类型 int*
的对象一样(6.5/ 7“严格别名”)。
这里真正的问题是为什么你要使用这样的联合而不是总是通过
unsigned int*
访问内存,然后在需要时将取消引用的值转换为 int
。
标准不清楚是否通过左值进行访问,例如:
addressOfStructOrUnion->member
是为了考虑使用结构或联合类型的左值或成员类型的左值执行的别名规则。我认为委员会成员在这一点上从未达成过共识。
clang 和 gcc 解释标准的方式,将假定
addressOfStructOrUnion->member
形式的左值无法访问 addressOfDifferentStructOrUnion->member
形式之一,即使成员类型相同。此外,即使标准明确表示 addressOfStructOrUnion->memberArray[index]
形式的左值等同于 *(addressOfStructOrUnion->memberArray+(index))
,这显然是最终指针目标类型的左值(这又是数组的元素类型), clang 和 gcc 都将使用括号表示法通过表达式进行的访问视为通过结构或联合类型的左值进行的访问。
最好将标准视为定义了 C 的两种方言,其中一种表现得好像省略了 N1570 6.5p7(当使用
-fno-strict-aliasing
标志调用时,clang 和 gcc 将处理),另一种是仅适用于在每个单独存储的整个生命周期中始终以相同方式访问它的程序。