I'm attempting to write a generic version of __builtin_clz
that handles all integer types, including signed ones. To ensure that conversion of signed to unsigned types doesn't change the bit representation, I decided to use reinterpret_cast
.
I've got stuck on int64_t
which unlike the other types doesn't seem to work with reinterpret_cast
.
I would think the code below is correct but it generates a warning in GCC.
#include <cstdint>
int countLeadingZeros(const std::int64_t value)
{
static_assert(sizeof(std::int64_t) == sizeof(unsigned long long));
return __builtin_clzll(reinterpret_cast<const unsigned long long&>(value));
}
(demo)
GCC shows a warning: dereferencing type-punned pointer will break strict-aliasing rules
.
Clang compiles it without a complaint.
Which compiler is right? If it is GCC, what is the reason for the violation of strict-aliasing?
Edit: After reading the answers, I can see that the described behavior applies not only to conversion int64_t
-> unsigned long long
but also to long
-> long long
. The latter one makes the problem a little more obvious.