【问题标题】:Does this union break strict aliasing? What about floating point registers这个联合会破坏严格的别名吗?浮点寄存器呢
【发布时间】:2012-09-06 09:32:13
【问题描述】:
union
{
    Uint32 Integer;
    Float32 Real;
} Field;    

我必须使用那个联合来实现一点 IEEE 技巧,这会破坏严格的别名吗? GCC 没有发出任何警告(尝试使用 GCC 4.5 和 4.6,即使使用迂腐的严格别名,但据我所知,GCC 并不能很好地捕捉严格的别名规则违规行为(大量误报/误报)。

Field A;
A.Integer = (Value1 & B) || Value2;
return A.Real;

这是我目前使用的 sn-p,它似乎可以正常工作而没有任何警告,但某些编译器优化可能会产生副作用或未定义的行为。所以如果那段代码在某些情况下可能是不安全的,我会努力删除它。

我还假设这段代码需要将数据从标准寄存器移动到大多数现代 CPU 上的浮点寄存器(只是好奇),这涉及到一些与旧 CPU 相关的额外周期,对吗?

上面的代码不是为了优化,所以请不要贬低我滥用优化,上面的代码是我获得某个结果的最简单方法(幸运的是,最简单的方法似乎也是在我的情况下是最快的!),如果结果不安全,那么我会使用更慢的方式。

提前致谢

【问题讨论】:

    标签: c++ gcc unions floating strict-aliasing


    【解决方案1】:

    通过联合的别名在 C 中定义,但在 C++ 中具有未定义的行为;未定义的行为等同于从未初始化的变量读取时发生的行为(左值到右值的转换)。

    因此,最有可能破坏的方式是优化器决定消除联合中的读取,因为它没有定义的值。但是,大多数 C 和 C++ 编译器可能会为您提供 C 行为,因为它们无论如何都需要支持。

    给值取别名的安全方法是通过字节复制,例如std::memcpystd::copy(reinterpret_cast<char *>(...), ...)。或者,如果您可以在 C 和 C++ 中编译您的项目,您可以将联合别名代码移动到 C 源文件并将该代码编译为 C。

    【讨论】:

    • 您确定按位复制符合标准吗?从技术上讲,您首先将float 读取为char[4](可以),然后在RHS 的内存位置写入char[4],然后将char[4] 别名为int,这是不允许的严格的别名规则。
    • @Kos 向/从char 的数组进行字节复制在 3.9p2 中描述,在 3.9p3 中描述了直接字节复制,因此不会违反别名。需要注意的是,该标准仅涵盖具有相同类型的源和目标。
    【解决方案2】:

    它是 UB(但不需要严格的别名)。此外,uniond 数据始终由实现存储在内存中,AFAIK,否则需要知道源数据来自哪个寄存器,这意味着知道源类型。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-10-15
      • 2013-07-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-11-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多