我有以下代码:
typedef unsigned char uchar;
constexpr int leaing_ones(uchar const u8) noexcept {
return __builtin_clz(static_cast<uchar>(~static_cast<unsigned>(u8))) +
sizeof(uchar) * 8 - sizeof(int) * 8;
}
int main() {
static_assert(leaing_ones(0b0000'0000) == 0);
static_assert(leaing_ones(0b1000'0000) == 1);
static_assert(leaing_ones(0b1100'0000) == 2);
static_assert(leaing_ones(0b1110'0000) == 3);
static_assert(leaing_ones(0b1111'0000) == 4);
static_assert(leaing_ones(0b1111'1000) == 5);
static_assert(leaing_ones(0b1111'1000) == 5);
static_assert(leaing_ones(0b1111'1100) == 6);
static_assert(leaing_ones(0b1111'1110) == 7);
static_assert(leaing_ones(0b1111'1111) == 8);
}
我 tested 这些与 clang 12 和 GCC 11.1。唯一的问题是 clang 特别不喜欢最后一个断言:
<source>:16:17: error: static_assert expression is not an integral constant expression
static_assert(leaing_ones(0b1111'1111) == 8);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
据我所知,我没有造成任何类型的溢出,而且 GCC 可以很好地处理所有这些问题。这是一个叮当声错误,还是我忽略了什么?
答案 0 :(得分:2)
将 0
传递给 __builtin_clz
是 UB。
来自GCC manual:
<块引用>返回 x 中前导 0 位的数量,从最高有效位位置开始。 如果 x 为 0,则结果未定义。
(我的粗体)
答案 1 :(得分:2)
__builtin_clz
is undefined for an argument with value zero,并且由于您反转所有位,因此 0b1111'1111
成为全零的模式。您的函数需要特殊情况 0
才能使用适当的值。