将结构映射到uint64_t
将下面的结构转换为的正确方法是什么uint64_t?
struct Data
{
uint64_t sign : 1;
uint64_t exp : 4;
uint64_t man : 8;
};
static_assert(sizeof(Data) == sizeof(uint64_t));
显而易见的是
Data data;
uint64_t n = *(reinterpret_cast<const uint64_t*>(&data));
但它不会编译为constexpr并在 GCC 中产生以下警告:
dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
编辑1:
result 的值uint64_t可能因编译器不同而不同。但是当我将它从uint64_t.
所以,更准确地说我需要:
Data data;
uint64_t n = convert(data);
Data data2 = convert_back(n);
static_assert(data == data2);
回答
转换不是“显而易见的”,因为 的确切布局Data是实现定义的(参见位域)。此外,正如错误所暗示的那样,您通过指针进行的转换会破坏严格的别名。没有uint64_t存储在 的地址data。
你可以像这样转换它:
constexpr uint64_t Data_2_uint(const Data& d){
return d.sign + (d.exp << 1) + (d.man << 5);
}
回答
您std::memcpy将结构转换为uint64_t. std::memcpy是执行类型双关的合法方式,它是允许的,因为您的结构是可简单复制的。
在 C++20 中也有std::bit_cast.
与std::memcpyit's不同constexpr,但为了使其在编译时工作,我必须uint64_t : 51;在结构的末尾添加。
有趣的是,Clang(与 GCC 和 MSVC 不同)拒绝在编译时执行它:
note: constexpr bit_cast involving bit-field is not yet supported