Remove some stdbit.h bit-precise integer restrictions

ISO/IEC JTC1/SC22/WG14 N3922 2026-07-12

Jakub Jelínek, jakub@redhat.com

Abstract
ChangeLog
    Revision 0
Introduction and Motivation
Wording
Acknowledgments

Abstract

This paper proposes dropping some restrictions on use of bit-precise integer types in stdbit.h type-generic macros.

ChangeLog

Revision 0 2026-07-12

— Initial release.

Introduction and Motivation

C23 introduced bit-precise integer types, however various restrictions on stdbit.h type-generic macros make the bit-precise integer types second class citizens. The usual wording is: a bit-precise unsigned integer type whose width matches a standard or extended integer type.

If a C23 or C2Y implementation implements the bare minimum bit-precise integer types (so e.g. with BITINT_MAXWIDTH equal to LLONG_WIDTH or perhaps twice as big value), modifying all of the stdbit.h type-generic macros to also support arbitrary supported bit-precise integer types is fairly easy. In some cases it is just a matter of zero-extending the value into the largest standard or extended integer type, in other cases one needs to query the width of the bit-precise integer type (can be done using _Generic or e.g. using stdc_count_ones on (unsigned long long) ~(typeof (value))0) and combine that with the result of the type-generic macro on a larger standard or extended integer type. Or, if it is twice the size of the largest standard or extended integer type, it can be often implemented using the type-generic macro on both the low and high halves of the value cast to the largest standard or extended integer type.

If an implementation already supports much larger values of BITINT_MAXWIDTH, then significant effort has already been spent to implement arithmetics, cast from/to floating point types (including decimal floating point) and implementing extra type-generic intrinsics for the stdbit.h type-generic macros is just a very small fraction of the overall engineering effort to implement bit-precise integer types.

Both GCC and Clang implement various built-in functions which can be used to implement stdbit.h macros, e.g. __builtin_clzg, __builtin_ctzg, __builtin_clrsbg, __builtin_ffsg, __builtin_parityg, __builtin_popcountg, __builtin_bswapg, __builtin_bitreverseg, and __builtin_stdc_bit_ceil, __builtin_stdc_bit_floor, __builtin_stdc_bit_width, __builtin_stdc_count_ones, __builtin_stdc_count_zeros, __builtin_stdc_first_leading_one, __builtin_stdc_first_leading_zero, __builtin_stdc_first_trailing_one, __builtin_stdc_first_trailing_zero, __builtin_stdc_has_single_bit, __builtin_stdc_leading_ones, __builtin_stdc_leading_zeros, __builtin_stdc_rotate_left, __builtin_stdc_rotate_right, __builtin_stdc_trailing_ones, __builtin_stdc_trailing_zeros. With these, e.g. the GNU C library supports in stdbit.h arbitrary bit-precise integer types without too much extra effort.

If width of bit-precise unsigned integer needs to be determined amd BITINT_MAXWIDTH is large, one possibility is using __builtin_popcountg(~(typeof(val))0), another one provided the largest known ABI limb width is e.g. 128 is to use _Generic with associations for bit-precise integers with width from 1 to 127 and then sizeof(val)*CHAR_BIT, sizeof(val)*CHAR_BIT-1 down to sizeof(val)*CHAR_BIT-127 guarded so that it is never larger than BITINT_MAXWIDTH and finally if needed some widths near BITINT_MAXWIDTH.

Wording

The wording is relative to the latest Working Draft at time of publication, N3886.

Modify 7.18.3 Count Leading Zeros paragraph 2:

Returns the number of consecutive 0 bits in value, starting from the most significant bit.
The type-generic function stdc_leading_zeros returns the appropriate value based on the type of the input value, provided that it is:
— a standard unsigned integer type;
— an extended unsigned integer type; or,
— a bit-precise unsigned integer type whose width matches a standard or extended integer type
an unsigned integer type.
The generic_return_type type shall be a suitably large unsigned integer type capable of representing the computed result.

Modify 7.18.4 Count Leading Ones paragraph 2:

Returns the number of consecutive 1 bits in value, starting from the most significant bit.
The type-generic function stdc_leading_ones returns the appropriate value based on the type of the input value, provided that it is:
— a standard unsigned integer type;
— an extended unsigned integer type; or,
— a bit-precise unsigned integer type whose width matches a standard or extended integer type
an unsigned integer type.
The generic_return_type type shall be a suitably large unsigned integer type capable of representing the computed result.

Modify 7.18.5 Count Trailing Zeros paragraph 2:

Returns the number of consecutive 0 bits in value, starting from the least significant bit.
The type-generic function stdc_trailing_zeros returns the appropriate value based on the type of the input value, provided that it is:
— a standard unsigned integer type;
— an extended unsigned integer type; or,
— a bit-precise unsigned integer type whose width matches a standard or extended integer type
an unsigned integer type.
The generic_return_type type shall be a suitably large unsigned integer type capable of representing the computed result.

Modify 7.18.6 Count Trailing Ones paragraph 2:

Returns the number of consecutive 1 bits in value, starting from the least significant bit.
The type-generic function stdc_trailing_ones returns the appropriate value based on the type of the input value, provided that it is:
— a standard unsigned integer type;
— an extended unsigned integer type; or,
— a bit-precise unsigned integer type whose width matches a standard or extended integer type
an unsigned integer type.
The generic_return_type type shall be a suitably large unsigned integer type capable of representing the computed result.

Modify 7.18.7 First Leading Zero paragraph 2:

Returns the most significant index of the first 0 bit in value, plus 1. If it is not found, this function returns 0.
The type-generic function stdc_first_leading_zero returns the appropriate value based on the type of the input value, provided that it is:
— a standard unsigned integer type;
— an extended unsigned integer type; or,
— a bit-precise unsigned integer type whose width matches a standard or extended integer type
an unsigned integer type.
The generic_return_type type shall be a suitably large unsigned integer type capable of representing the computed result.

Modify 7.18.8 First Leading One paragraph 2:

Returns the most significant index of the first 1 bit in value, plus 1. If it is not found, this function returns 0.
The type-generic function stdc_first_leading_one returns the appropriate value based on the type of the input value, provided that it is:
— a standard unsigned integer type;
— an extended unsigned integer type; or,
— a bit-precise unsigned integer type whose width matches a standard or extended integer type
an unsigned integer type.
The generic_return_type type shall be a suitably large unsigned integer type capable of representing the computed result.

Modify 7.18.9 First Trailing Zero paragraph 2:

Returns the least significant index of the first 0 bit in value, plus 1. If it is not found, this function returns 0.
The type-generic function stdc_first_trailing_zero returns the appropriate value based on the type of the input value, provided that it is:
— a standard unsigned integer type;
— an extended unsigned integer type; or,
— a bit-precise unsigned integer type whose width matches a standard or extended integer type
an unsigned integer type.
The generic_return_type type shall be a suitably large unsigned integer type capable of representing the computed result.

Modify 7.18.10 First Trailing One paragraph 2:

Returns the least significant index of the first 1 bit in value, plus 1. If it is not found, this function returns 0.
The type-generic function stdc_first_trailing_one returns the appropriate value based on the type of the input value, provided that it is:
— a standard unsigned integer type;
— an extended unsigned integer type; or,
— a bit-precise unsigned integer type whose width matches a standard or extended integer type
an unsigned integer type.
The generic_return_type type shall be a suitably large unsigned integer type capable of representing the computed result.

Modify 7.18.11 Count Zeros paragraph 3:

The type-generic function stdc_count_zeros returns the previously described result for a given input value provided that the type of the generic_value_type argument is:
— a standard unsigned integer type;
— an extended unsigned integer type; or,
— a bit-precise unsigned integer type whose width matches a standard or extended integer type
an unsigned integer type.
The generic_return_type type shall be a suitably large unsigned integer type capable of representing the computed result.

Modify 7.18.12 Count Ones paragraph 2:

Returns the total number of 1 bits within the given value.
The type-generic function stdc_count_ones returns the previously described result for a given input value the generic_value_type is:
— a standard unsigned integer type;
— an extended unsigned integer type; or,
— a bit-precise unsigned integer type whose width matches a standard or extended integer type
an unsigned integer type.
The generic_return_type type shall be a suitably large unsigned integer type capable of representing the computed result.

Modify 7.18.13 Single-bit Check paragraph 2:

The stdc_has_single_bit functions return true if and only if there is a single 1 bit in value.
The type-generic function stdc_has_single_bit returns the previously described result for a given input value provided that the type of the generic_value_type argument is:
— a standard unsigned integer type;
— an extended unsigned integer type; or,
— a bit-precise unsigned integer type whose width matches a standard or extended integer type
an unsigned integer type.

Modify 7.18.14 Bit Width paragraph 3:

The stdc_bit_width functions return 0 if value is 0. Otherwise, they return 1 + ⌊log2 (value)⌋.
The type-generic function stdc_bit_width returns the previously described result for a given input value provided that the type of the generic_value_type argument is:
— a standard unsigned integer type;
— an extended unsigned integer type; or,
— a bit-precise unsigned integer type whose width matches a standard or extended integer type
an unsigned integer type.
The generic_return_type type shall be a suitably large unsigned integer type capable of representing the computed result.

Modify 7.18.15 Bit Floor paragraph 3:

The stdc_bit_floor functions return 0 if value is 0. Otherwise, they return the largest integral power of 2 that is not greater than value.
The type-generic function stdc_bit_floor returns the previously described result for a given input value the generic_value_type is:
— a standard unsigned integer type;
— an extended unsigned integer type; or,
— a bit-precise unsigned integer type whose width matches a standard or extended integer type
an unsigned integer type.

Modify 7.18.16 Bit Ceiling paragraph 3:

The stdc_bit_ceil functions return the smallest integral power of 2 that is not less than value or 0 if such a value is not representable in the return type.
The type-generic function stdc_bit_ceil returns the previously described result for a given input value provided that the type of the generic_value_type argument is:
— a standard unsigned integer type;
— an extended unsigned integer type; or,
— a bit-precise unsigned integer type whose width matches a standard or extended integer type
an unsigned integer type.

Modify 7.18.17 Rotate Left paragraph 5:

The type-generic function stdc_rotate_left returns the above described result for a given input value provided that the type of the generic_value_type argument is:
— a standard unsigned integer type;
— an extended unsigned integer type; or,
— a bit-precise unsigned integer type whose width matches any standard or extended integer type
an unsigned integer type.
The count argument to the type-generic function stdc_rotate_left shall be a value of signed or unsigned integer type, or char.

Modify 7.18.18 Rotate Right paragraph 5:

The type-generic function stdc_rotate_right returns the above described result for a given input value provided that the type of the generic_value_type argument is:
— a standard unsigned integer type;
— an extended unsigned integer type; or,
— a bit-precise unsigned integer type whose width matches any standard or extended integer type
an unsigned integer type.
The count argument to the type-generic function stdc_rotate_right shall be a value of signed or unsigned integer type, or char.

Acknowledgments

Many thanks to Joseph S. Myers, Martin Uecker and Aaron Ballman.