static_assert 表达式不是带有 __builtin_clz 的整数常量表达式

时间:2021-06-04 17:42:03

标签: c++ clang

我有以下代码:

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 可以很好地处理所有这些问题。这是一个叮当声错误,还是我忽略了什么?

2 个答案:

答案 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 才能使用适当的值。