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 enput 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, implemantations 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.
#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("Input: 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 a 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 behavior.
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;
}