我有一个大型程序,其中包含大量
形式的片段float t = amplitudes->read(current_element);
if ( *((uint32_t * ) &t) == 0xsomereservedvalue)
do_something
else
do_something_else
这与gcc 3.4.x编译没有警告。使用-Wtrict-aliasing = 2编译仍然没有警告。我最近尝试使用gcc4.4进行编译,并获得了大量关于类型惩罚引用的警告。有人能告诉我有没有合理的情况下这种代码会失败?据我所知,如果优化排列的东西可以在另一行代码读取后从寄存器写回来,那么输入punning只是一个潜在的问题,因为我们在这里返回一个函数根本无法发生。我在这里遗漏了什么,或者gcc有点脑死亡?
答案 0 :(得分:1)
当然它警告说。我刚刚检查了gcc 4.8.2它也发出了警告。想象一下,目标机器的浮点大小是16位,你试图在数据绑定后读取32位。这是UB。
btw在这种情况下,我不同意reinterpret_cast的用法。 reinterpret_cast唯一有用的方法是*(reinterpret_cast<char *>(&t))
,即使*(reinterpret_cast<unsigned *>(&t))
仍会破坏别名规则,您也会得到相同的警告。这是因为编译器只在C ++中知道char是最小的,因此每种类型都可以转换为它。
GCC有一个属性来告诉给定类型可能是别名。它也不是那么容易使用。
unsigned * __attribute__ ((__may_alias__)) pu = (unsigned *) &t;
if (*pu == 0xsomereservedvalue)
do_something ();
else
do_something_else ();
但这里的事情至少是有道理的。我们要求使用别名指针。成本:代码现在不可移植。
因此,经过所有考虑后,如果您确定自己知道自己在做什么,我建议您只提供-fno-strict-aliasing
选项。
答案 1 :(得分:1)
“解除引用类型 - 惩罚指针将破坏严格别名”告诉您编译器可能正在进行可能会破坏您的代码的优化。
这可能发生的原因是允许编译器(根据语言规范)假设您只访问具有自己的类型或char类型的数组。
为了保证正确性,必须在禁用严格别名的情况下使用memcpy
进行打字或构建。 (工会有点不清楚)
请查看here,了解有关严格别名的其他详细信息。