Before C23, if you wanted to count the leading zeros in an integer or compute its population count, you either reached for GCC's __builtin_clz and __builtin_popcount, wrote a loop, or pulled in a platform-specific intrinsic. None of these were portable. stdbit.h (C23) standardises bit-manipulation operations so you can use them without the compiler-specific spellings.
#include <stdbit.h> unsigned int x = 0b00101100; // 44 stdc_leading_zeros(x) // 26 (zero bits before the highest set bit) stdc_leading_ones(x) // 0 stdc_trailing_zeros(x) // 2 (zero bits at the low end) stdc_trailing_ones(x) // 0 stdc_count_ones(x) // 3 (population count / Hamming weight) stdc_count_zeros(x) // 29 stdc_has_single_bit(x) // false (not a power of two) stdc_bit_width(x) // 6 (minimum bits needed to represent x) stdc_bit_floor(x) // 32 (largest power of two <= x) stdc_bit_ceil(x) // 64 (smallest power of two >= x)
The functions are generic: they accept any unsigned integer type and work on its full width. Passing a signed type is a constraint violation.
The same operations existed before C23 — ffs in <strings.h>, GCC's __builtin_* family, POSIX <strings.h>. The problem was inconsistent naming and undefined behaviour on zero inputs. The <stdbit.h> functions are defined for all valid inputs including zero, so stdc_leading_zeros(0) returns the full bit width of the type, not undefined behaviour.
stdc_bit_ceil and stdc_bit_floor replace the classic “next power of two” trick (1u << (32 - __builtin_clz(n))) which was easy to get wrong on edge cases like zero or already-a-power-of-two inputs.