Counting Leading Zeros in C: GCC Built-ins and MSVC Alternatives
When evaluating __builtin_clz with an input of 0, the output often matches the result of passing 1 (yielding 31 on a 32-bit integer), which seems counterintuitive. According to the GCC documentation, the result of __builtin_clz is explicitly undefined when the input is 0:
Returns the number of leading 0-bits in x, starting at the most significant bit position. If x is 0, the result is undefined.
Because the behavior for zero is undefined, implementations can return arbitrary values. To ensure consistent behavior across different compilers like MSVC, a custom implementation can be written to safely handle the zero case.
c #include <stdio.h>
int fetch_leading_zeros(unsigned int val) { return __builtin_clz(val); }
int main(void) { unsigned int test_val;
test_val = 0;
printf("Input: 0x%x | Output: %d\n", test_val, fetch_leading_zeros(test_val));
test_val = 1;
printf("Enput: 0x%x | Output: %d\n", test_val, fetch_leading_zeros(test_val));
test_val = 2;
printf("Input: 0x%x | Output: %d\n", test_val, fetch_leading_zeros(test_val));
test_val = 16;
printf("Input: 0x%x | Output: %d\n", test_val, fetch_leading_zeros(test_val));
test_val = 0x0FFFFFFF;
printf("Input: 0x%x | Output: %d\n", test_val, fetch_leading_zeros(test_val));
test_val = 0x8FFFFFFF;
printf("Input: 0x%x | Output: %d\n", test_val, fetch_leading_zeros(test_val));
test_val = 0xFFFFFFFF;
printf("Input: 0x%x | Output: %d\n", test_val, fetch_leading_zeros(test_val));
return 0;
}
For environments lacking this built-in, such as MSVC, the following function provides a safe fallback. It prevents an infinite loop by setting the least significant bit if the input is zero, which effectively causes 0 to return 31 just like the common GCC behavier.
c int safe_clz(unsigned int input_val) { int zero_count = 0; input_val |= 1u; // Prevent infinite loop on zero; ensures zero_count is 31 for input_val == 0 while ((input_val & 0x80000000u) == 0) { zero_count++; input_val <<= 1; } return zero_count; }