在以下代码中:
t
严格的别名规则是否会被破坏?据我所知,它确实如此,因为指向短点的指针指向int。但编译器即使编译时也不会抱怨(假设代码在test.c中)
#include <stdio.h>
int main(void)
{
int n = 74;
int * pn = &n;
short * sp;
//sp = (short *)&n; // <-- bad
sp = (short *)pn; // <-- fine
*sp = 4;
printf("%d\n", *sp);
return 0;
}
但是,如果标记为“坏”的行被取消注释,并且标记为“罚款”的行被注释,则会发出抱怨。
有人可以解释一下这个案子真的违反了规则吗?如果是这样,为什么编译器没有检测到它?如果没有,为什么不,因为按照标准应该呢?
答案 0 :(得分:2)
违反严格别名的不是转换本身,而是违反它的后续无效左值访问(内存重新解释)。
严格别名冲突实际上是运行时违规:它们是通过作为左值访问的对象的动态类型定义的。因此,在编译时并不总是能够捕获严格别名违规。
请考虑以下代码段
short n = 0;
int *pn = (int *) &n; // 1
short *sp = (short *) pn; // 2
*sp = 4;
此代码不违反严格别名规则,即使它包含与原始代码相同的强制转换(2)。尽管指针pn
被声明为int *
,但在运行时它实际上指向类型为short
的对象。因此,对short *
的强制转换以及随后对指针对象的赋值完全有效。 (假设指针值在此往返演员中幸存下来。)
在这样的情况下,编译器显然努力捕获转换链中的第一个转换:看起来是潜在的严格别名违规的相当明显的前提 - 在我的示例中转换为1。 Cast 2具有相当高的产生误报的可能性(如我的例子中所示),并且编译器不会对其发出警告。
答案 1 :(得分:2)
编译器很难在编译时捕获违规,除非您通过解除引用分配一个新值到另一个类型,如下所示。如果您更改了如下所示的代码,您将收到预期的警告。
int main(void)
{
int n = 74;
//int * pn = &n;
//short * sp;
//sp = (short *)&n; // <-- bad
//sp = (short *)pn; // <-- fine
*((short*)&n) = 4;
printf("%d\n", n);
return 0;
}
此问题显示完全相同的问题,并提供更多详细信息。 GCC: accuracy of strict aliasing warnings
AnT的另一个答案始于以下声明: “这不是违反严格别名的转换本身,而是违反它的后续无效左值访问(内存重新解释)。” .... 那是正确的。我的示例尝试违反规则的左值访问,以便您收到警告。