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

static_assert expression is not an integral constant expression with __builtin_clz

我有以下代码:

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

0 传递给 __builtin_clz 是未定义的行为。

来自GCC manual

Returns the number of leading 0-bits in x, starting at the most significant bit position. If x is 0, the result is undefined.

(大胆的矿)

__builtin_clz is undefined for an argument with value zero,并且由于您反转了所有位,因此 0b1111'1111 成为全零的模式。您的函数需要特殊情况 0 才能使用适当的值。