const / static 初始值设定项中的类型双关语(从位构建浮点常量)

dat*_*olf 1 c++ type-punning

某些语言(如 Rust、Zig、GLSL、HLSL)具有内置方法,可根据作为无符号整数提供的位构建浮点类型。然而,C 和 C++ 没有这方面的标准函数。

在 C99 中,我们可以使用带有成员初始化的匿名联合来实现类型双关宏,以达到相同的效果:

#define FLOAT_FROM_BITS(U,F,b) (((union{U u; F f;}){.u=(b)}).f)
#define FLOAT32_FROM_BITS(i) FLOAT_FROM_BITS(uint32_t, float,  i)
#define FLOAT64_FROM_BITS(i) FLOAT_FROM_BITS(uint64_t, double, i)
Run Code Online (Sandbox Code Playgroud)

随后可以使用它来初始化 const / static。在 C++ 中执行此操作最优雅的方法是什么,以便它也可以用于静态初始化?

Nat*_*ica 5

如果你可以使用C++20或更高版本,那么使用std::bit_castlike

auto myvar = std::bit_cast<type_to_cast_to>(value_to_cast);
Run Code Online (Sandbox Code Playgroud)

如果您想支持旧版本,可以使用std::memcpy将字节从一种类型复制到另一种类型来执行相同的操作。这会给你一个像这样的函数

template <class To, class From>
To bit_cast(const From& src)
{
    To dst;
    std::memcpy(&dst, &src, sizeof(To));
    return dst;
}
Run Code Online (Sandbox Code Playgroud)

  • @datenwolf 我做了一些实验,看来 GCC 从未将“mov eax, CONSTANT”与浮点数一起使用。它仅将其与整数一起使用。即使使用 constexpr 值,它也会使用“movss xmm0, DWORD PTR .LCx[rip]”将值加载到寄存器中。与使用“std::memcpy”的唯一区别是它在启动时将值复制到内存中(使用相同的技巧“mov DWORD PTR c1[rip], CONSTANT”)而不是使用只读段。 (2认同)