org: | ISO/IEC JCT1/SC22/WG14 | document: | N2888 | ||||
target: | IS 9899:2023 | version: | 2 | ||||
date: | 2021-12-1 | license: | CC BY |
Paper number | Title | Changes | |
---|---|---|---|
N2821 | Require exact-width integer type interfaces | Initial version | WG14 poll: largly in favour |
N2872 | Require exact-width integer type interfaces v1 | replaces N2821 | wording change, first change → C23 |
N2888 | Require exact-width integer type interfaces v2 | replaces N2872 | changes for #if |
C23 already simplifies the integer model in two important aspects. First, it only has two’s complement as the sign representation of integer types and, second, we also do not allow sign bits to be masked out for a corresponding unsigned integer type. So we have gained guarantees for the homogeneity of integer representations and for the absence of padding in a general framework.
Besides bool
, most platforms have standard or extended integer types without padding bits, so usually they can be used (and are used) through the typedefs of the form [u]intN_t
. There is no apparent technical reason that such integer types are not exposed as exact-width integer types, so for the sake of the programmer’s comfort we propose to make them mandatory where they may.
On the other hand the [u]intmax_t
ABI freeze inhibits any progress on platforms that want to add new, wider, integer types even if they fulfill the requirements for [u]intN_t
. The notorious example for this is gcc. On most modern platforms it has type __int128_t
and the corresponding unsigned type (soft or hard), but this type cannot be added to the platform as an extended integer type because of the ABI freeze.
The demand for integer types with 128
and 256
bits is increasing, other languages start to have them among their required types. We should not wait another normalization cycle (12 years so far) to make this happen. Thus we propose to allow such extended types in a restricted setting, namely where they are such that they can (and must with the above) be interfaced as exact-width integer type.
The following change has already been voted into C23.
These types are optional. However, ifIf an implementation provides standard or extended integer types withwidths of 8, 16, 32, or 64a particular width and no padding bits, it shall define the corresponding typedef names.
Since C23 reforms the possible integer types, there is not much reason that an implementation that has such types should not announce them through these interfaces. Most implementations probably to do so anyhow; their addition to the header is of minimal overhead.
NB: The insertion of standard or extended ensures consistency with the new bit-precise integer types that are added in C23.
The impact for implementations should be minimal. This change only requires them to newly publish a type (that has not a width of 8
, 16
, 32
or 64
) and all depending macros in a standardized form that is already present on the platform either as standard integer type (very unlikely) or as extended integer type (currently not heard of). The only additional implementation effort could be for an extended type for which there would not yet be specifiers for formatted IO. As these extended types are never heard of up to now, existence of a platform that such a lacks such specifiers is very unlikely.
No ABI changes are intended.
It only changes perception of the platform for user code if that code is recompiled and queries for types outside the spectrum that the header offers so far, most likely for values for N of 24
, 48
, 96
, or 128
. This impact is intended.
The following type designates a signed integer type capable of representing any value of any signed integer type with the possible exception of signed extended integer types that are wider than
long long
and that are referred by the type definition for an exact with integer type:
The following type designates the unsigned integer type
capable of representing any value of any unsigned integer typethat corresponds tointmax_t
FNT1:
These types are required.
FNT1 Thus this type is capable of representing any value of any unsigned integer type with the possible exception of particular extended integer types that are wider than unsigned long long
.
Because [u]intmax_t
is part of platform ABIs, currently implementations are stuck on their current integer model. They can’t add new wider integer types on new sub-architectures and can’t even offer soft-emulations for such types.
WG14 has discussed this a lot over the last years and partially taken action to accommodate that failure; in particular C23 will offer possibilities in printf
and scanf
to input and output types that are wider than [u]intmax_t
. This addition makes it now possible to add extended types and macros that match the requirements of [u]intN_t
.
The fact that platforms are not extendable for new integer types has not been completely addressed, yet. We should not delay that another 12 years.
Because it only widens permissions for implementations, the change has no impact on existing implementations or user code.
In contrast to that, platforms that want to add new integer types without padding that are wider than ULLONG_WIDTH
, e.g via a soft-emulation, may do so and interface them as uintN_t
.
The new conversion specifications then allow such platforms to print or scan these types; PRI
and SCN
macros can point to the corresponding formats.
Integer constants for these types can be implemented in the usual way. Instead of producing an error when they are larger than ULLONG_MAX
, e.g, the platform just has to switch type to their wider extended type. Such constants are valid preprocessor numbers. They would simply not be available as constants in preprocessor conditionals, but with the introduction of the [U]INT..._WIDTH
feature macros a need for that in new code should seldom arise.
The effect of the previous change is that the maximum and minimum values that correspond to types that are wider than [u]intmax_t
may not fit for preprocessor arithmetic.
3 Each invocation of one of these macros shall expand to an integer constant expression
suitable for use in. The type of the expression shall have the same type as would an expression of the corresponding type converted according to the integer promotions. The value of the expression shall be that of the argument. If the value is in the range of the type#if
preprocessing directivesintmax_t
(for a signed type) or the typeuintmax_t
(for an unsigned type), see 7.20.1.5, the expression is suitable for use in#if
preprocessing directives.
It only has impact on platforms that add new types that are wider than [u]intmax_t
. Existing code on platforms with no changes with respect to these types should not be affected.
User code that queries for UINT128_C
, say, and then uses a constant such as UINT128_C
(3402823669209384634
63374607431768211455)
in a preprocessing conditional on platforms that newly adds a 128 type that does not fit uintmax_t
may have to adjust.
<limits.h>
) p2 and p3The effect of the previous change is that the maximum and minimum values that correspond to types that are wider than [u]intmax_t
may not fit for preprocessor arithmetic.
2 For all unsigned integer types for which
<limits.h>
or<stdint.h>
define a macro with suffix_WIDTH
holding its width N, there is a macro with suffix_MAX
holding the maximal value 2N − 1 that is representable by the type, that is suitable for use inand that has the same type as would an expression that is an object of the corresponding type converted according to the integer promotions. If the value is in the range of the type#if
preprocessing directivesuintmax_t
(7.20.1.5) the macro is suitable for use in#if
preprocessing directives.
3 For all signed integer types for which
<limits.h>
or<stdint.h>
define a macro with suffix_WIDTH
holding its width N, there are macros with suffix _MIN and _MAX holding the minimal and maximal values − 2N − 1 and 2N − 1 − 1 that are representable by the type, that are suitable for use inand that have the same type as would an expression that is an object of the corresponding type converted according to the integer promotions. If the values are in the range of the type#if
preprocessing directivesintmax_t
(7.20.1.5) the macros are suitable for use in#if
preprocessing directives.
It only has impact on platforms that add new types that are wider than [u]intmax_t
. Existing code on platforms with no changes with respect to these types should not be affected.
User code that queries for UINT128_MAX
, say, on platforms that newly adds a 128 type that does not fit uintmax_t
may have to adjust. This would in many cases easily be done by either using #ifdef
or by using the UINT128_WIDTH
macro instead.