将结构映射到 uint64_t

Dmi*_*ano 4 c++

将下面的结构转换为的正确方法是什么uint64_t

struct Data
{
    uint64_t sign : 1;
    uint64_t exp : 4;
    uint64_t man : 8;
};

static_assert(sizeof(Data) == sizeof(uint64_t));
Run Code Online (Sandbox Code Playgroud)

显而易见的是

Data data;
uint64_t n = *(reinterpret_cast<const uint64_t*>(&data));
Run Code Online (Sandbox Code Playgroud)

但它不会编译为constexpr并在 GCC 中产生以下警告:

dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
Run Code Online (Sandbox Code Playgroud)

编辑1:

result 的值uint64_t可能因编译器不同而不同。但是当我将它从uint64_t.

所以,更准确地说我需要:

Data data;
uint64_t n = convert(data);
Data data2 = convert_back(n);
static_assert(data == data2);
Run Code Online (Sandbox Code Playgroud)

for*_*818 5

转换不是“显而易见的”,因为 的确切布局Data是实现定义的(参见位域)。此外,正如错误所暗示的那样,您通过指针进行的转换会破坏严格的别名。没有uint64_t存储在 的地址data

你可以像这样转换它:

constexpr uint64_t Data_2_uint(const Data& d){
    return d.sign + (d.exp << 1) + (d.man << 5);
}
Run Code Online (Sandbox Code Playgroud)


Hol*_*Cat 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
Run Code Online (Sandbox Code Playgroud)