Require exact-width integer type interfaces

Jens Gustedt, INRIA, France

org: ISO/IEC JCT1/SC22/WG14 document: N2888
target: IS 9899:2023 version: 2
date: 2021-12-1 license: CC BY

Revision history

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

Introduction

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.

Changes

Adopted change in 7.20.1.1 (Exact-width integer types) p3

The following change has already been voted into C23.

These types are optional. However, ifIf an implementation provides standard or extended integer types with widths of 8, 16, 32, or 64a particular width and no padding bits, it shall define the corresponding typedef names.

Rationale:

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.

Impact:

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.

Change in 7.20.1.5 (Greatest-width integer types) p1

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:

intmax_t

The following type designates the unsigned integer type capable of representing any value of any unsigned integer type that corresponds to intmax_tFNT1:

uintmax_t

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.

Rationale:

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.

Impact:

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.

Change in 7.20..4 (Macros for integer constants) p3

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 #if preprocessing directives. 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 intmax_t (for a signed type) or the type uintmax_t (for an unsigned type), see 7.20.1.5, the expression is suitable for use in #if preprocessing directives.

Impact:

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(340282366920938463463374607431768211455) in a preprocessing conditional on platforms that newly adds a 128 type that does not fit uintmax_t may have to adjust.

Change in 5.2.4.2.1 (Characteristics of integer types <limits.h>) p2 and p3

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.

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 in #if preprocessing directives and 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 uintmax_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 in #if preprocessing directives and 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 intmax_t (7.20.1.5) the macros are suitable for use in #if preprocessing directives.

Impact:

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.

Questions to WG14

  1. Shall we integrate Changes 3.2, 3.3 and 3.4 into C23?