What is the right way to convert the structure below to uint64_t
?
struct Data
{
uint64_t sign : 1;
uint64_t exp : 4;
uint64_t man : 8;
};
static_assert(sizeof(Data) == sizeof(uint64_t));
the obvious one is
Data data;
uint64_t n = *(reinterpret_cast<const uint64_t*>(&data));
but it does not compile as constexpr
and produces the following warnings in GCC:
dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
EDIT1:
The value of resulting uint64_t
may be different with different compilers. But the value of Data structure should be the same when I convert it back from uint64_t
.
So, saying more exactly I need:
Data data;
uint64_t n = convert(data);
Data data2 = convert_back(n);
static_assert(data == data2);
You std::memcpy
the structure to an uint64_t
. std::memcpy
is a legal way to perform type punning, it is allowed since your structure is trivially-copyable.
In C++20 there is also std::bit_cast
.
Unlike std::memcpy
it's constexpr
, but to make it work at compile-time I had to add uint64_t : 51;
at the end of the struct.
Interestingly, Clang (unlike GCC and MSVC) refused to perform it at compile-time:
note: constexpr bit_cast involving bit-field is not yet supported
The conversion is not "obvious" because the exact layout of Data
is implementation defined (see bit field). Moreover, your cast via pointers breaks strict aliasing, as the error suggests. There is no uint64_t
stored at the adress of data
.
You can convert it like this:
constexpr uint64_t Data_2_uint(const Data& d){
return d.sign + (d.exp << 1) + (d.man << 5);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With