首页 > 解决方案 > 位扫描转发作为 C 的编译时常量?

问题描述

bit-scan-forward 函数扫描第一位,例如:

assert(13 == __builtin_ctz(1 << 13));

给定一个在编译时已知的枚举,如何将 GCC__builtin_ctz或 MSVC 的结果_BitScanForward64作为编译时常量访问?

标签: cmacrosbit-manipulation

解决方案


发布答案,因为这可以通过对所有标志的详尽测试来实现。

此 Python 脚本定义BITSCAN_FTD_CONSTEXPR了一个适用于 32 位整数的宏,如果没有任何值匹配,则无法编译。

BITS = 32
parens = []
print("#define BITSCAN_FTD_CONSTEXPR_IMPL(a) \\")
for i in range(0, BITS + 1):
    print("    ((a) & (1u << %du) ? %d : \\" % (i, i))
print("    0", end="")
print(")" * (BITS + 1))
print(r'''
#define BITSCAN_FTD_CONSTEXPR(a) \
  ((sizeof(struct { int _isnt_zero : BITSCAN_FTD_CONSTEXPR_IMPL(a); }) ? \
        BITSCAN_FTD_CONSTEXPR_IMPL(a) : \
        0 /* Unreachable! */ ))''')
#define BITSCAN_FTD_CONSTEXPR_IMPL(a) \
    ((a) & (1u << 0u) ? 0 : \
    ((a) & (1u << 1u) ? 1 : \
    ((a) & (1u << 2u) ? 2 : \
    ((a) & (1u << 3u) ? 3 : \
    ((a) & (1u << 4u) ? 4 : \
    ((a) & (1u << 5u) ? 5 : \
    ((a) & (1u << 6u) ? 6 : \
    ((a) & (1u << 7u) ? 7 : \
    ((a) & (1u << 8u) ? 8 : \
    ((a) & (1u << 9u) ? 9 : \
    ((a) & (1u << 10u) ? 10 : \
    ((a) & (1u << 11u) ? 11 : \
    ((a) & (1u << 12u) ? 12 : \
    ((a) & (1u << 13u) ? 13 : \
    ((a) & (1u << 14u) ? 14 : \
    ((a) & (1u << 15u) ? 15 : \
    ((a) & (1u << 16u) ? 16 : \
    ((a) & (1u << 17u) ? 17 : \
    ((a) & (1u << 18u) ? 18 : \
    ((a) & (1u << 19u) ? 19 : \
    ((a) & (1u << 20u) ? 20 : \
    ((a) & (1u << 21u) ? 21 : \
    ((a) & (1u << 22u) ? 22 : \
    ((a) & (1u << 23u) ? 23 : \
    ((a) & (1u << 24u) ? 24 : \
    ((a) & (1u << 25u) ? 25 : \
    ((a) & (1u << 26u) ? 26 : \
    ((a) & (1u << 27u) ? 27 : \
    ((a) & (1u << 28u) ? 28 : \
    ((a) & (1u << 29u) ? 29 : \
    ((a) & (1u << 30u) ? 30 : \
    ((a) & (1u << 31u) ? 31 : \
    ((a) & (1u << 32u) ? 32 : \
    0)))))))))))))))))))))))))))))))))


#define BITSCAN_FTD_CONSTEXPR(a) \
  ((sizeof(struct { int _isnt_zero : BITSCAN_FTD_CONSTEXPR_IMPL(a); }) ? \
        BITSCAN_FTD_CONSTEXPR_IMPL(a) : \
        0 /* Unreachable! */ ))
  printf("Example: %i\n", BITSCAN_FTD_CONSTEXPR(1 << 12));

打印的Example: 12.


经测试可与 GCC-11 和 Clang-12 一起使用。


推荐阅读