Authors: Jay Ghiron
Date: 2026-05-01
Submitted against: C23
Status: Open
The minimum-width integer types do not properly consider padding or bit-precise integer types:
The typedef name
int_leastN_tdesignates a signed integer type with a width of at least N, such that no signed integer type with lesser size has at least the specified width. Thus,int_least32_tdenotes a signed integer type with a width of at least 32 bits.The typedef name
uint_leastN_tdesignates an unsigned integer type with a width of at least N, such that no unsigned integer type with lesser size has at least the specified width. Thus,uint_least16_tdenotes an unsigned integer type with a width of at least 16 bits.
(C23 7.22.2.3 "Minimum-width integer types" paragraphs 1 and 2.)
For example:
#include<stdint.h>
static_assert(UINT_LEAST16_WIDTH<=UINT_LEAST32_WIDTH);
Considering these are supposed to be the minimum-width integer types
it would be quite surprising if this static assertion might not hold.
But consider the following implementation: there are no extended
integer types, bytes are eight bits, short is sixty four bits with
thirty two bits being padding, int is sixty four bits with zero bits
being padding, long is more than sixty four bits with zero bits
being padding, and long long is sixty four bits with zero bits being
padding. The following definitions would then be valid:
typedef unsigned uint_least16_t;
typedef unsigned short uint_least32_t;
Meaning that UINT_LEAST16_WIDTH is sixty four and
UINT_LEAST32_WIDTH is thirty two. The current wording only
considers the size in terms of bytes, so it prevents
sizeof(uint_least16_t)>sizeof(uint_least32_t) but it seems
unintended to allow for the widths to be like this. It also means
that for this hypothetical implementation:
typedef unsigned uint_least16_t;
There is no preference as to which type (unsigned or unsigned short) can be chosen, so even though there is a type with a smaller
width uint_least16_t does not need to choose that type over the type
with the larger width. That is weird, but it does not seem too
important to try and restrict it. The fastest minimum-width integer
types similarly do not constrain the widths to prevent larger values
of N in int_fastN_t or uint_fastN_t from decreasing the
width, and using padding bits is not even necessary to imagine an
implementation that could use such weird definitions. It seems
unintended too since if int_fastN_t were wider than
int_fastM_t with N<M both types would be valid definitions
for both int_fastN_t and int_fastM_t. To define them that
way is to suggest that each type is faster than the other type, which
does not make sense.
For the issue with bit-precise integer types consider the following
implementation: there are no extended integer types, bytes are eight
bits, short is thirty two bits, int is thirty two bits, long is
sixty four bits, long long is sixty four bits, all standard integer
types have no padding bits, and _BitInt(24) has no padding bits.
int_least16_t should be defined either as short or as int, but
because _BitInt(24) exists there is now an integer type with a
lesser size than both that has at least sixteen bits in width.
int_least16_t cannot be defined as a bit-precise integer type, since
that is explicitly forbidden. Therefore it seems like such an
implementation is forbidden and _BitInt(24) must be given padding
bits, though that is surely unintended.
Modify C23 7.22.2.1 paragraph 2:
In the following descriptions, the symbol N represents an unsigned decimal integer with no leading zeros (e.g. 8 or 24, but not 04 or 048). When two typedef names differing only in the value of N are defined, the typedef name whose N has a larger value shall not denote a type which has a width less than the width of the type which the other typedef name denotes.
Modify C23 7.22.2.3 paragraphs 1 and 2:
The typedef name
int_leastN_tdesignates a signed integer type with a width of at least N, such that no signed integer type other than a bit-precise signed integer type with lesser size has at least the specified width. Thus,int_least32_tdenotes a signed integer type with a width of at least 32 bits.The typedef name
uint_leastN_tdesignates an unsigned integer type with a width of at least N, such that no unsigned integer type other than a bit-precise unsigned integer type with lesser size has at least the specified width. Thus,uint_least16_tdenotes an unsigned integer type with a width of at least 16 bits.