Posting an answer since this is possible with an exhaustive tests of all flags.
This Python script defines BITSCAN_FTD_CONSTEXPR
, a macro which works for 32bit integer, failing to compile if none of the values are matched.
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));
Print's Example: 12
.
Tested to work with GCC-11 & Clang-12.