JTC1/SC22/WG14
N851
SC22/WG14/N851
Changes to <inttypes.h> and <stdint.h>
Clive Feather
clive@demon.net
1998-09-22
[All references in this paper are to CD2.]
Summary
=======
The headers <inttypes.h> and <stdint.h> define symbols for integer types
with various properties. Most of these symbols contain a number,
representing the width of the type. Apart from the specific cases of 8, 16,
32, and 64, there is no requirement that such types have a sensible
definition. The proposed changes fix this.
This proposal does reserve symbols not already reserved. However, all such
symbols have the same format as those already in use.
Detailed description
====================
The definitions in <stdint.h> put requirements on the types it names, so
int16_t must have a width of exactly 16, and INT16_MAX must be 32767. But
there are no equivalent requirements on types such as int24_t or int128_t.
So it is possible for int24_t to be a 16 bit type, or int_least128_t to be
a 64 bit type. This is not in the interests of either the implementer or
the user of an implementation.
It could be argued that the marketplace will eliminate implementations with
such dubious definitions. But it is relatively simple to solve this problem
and I believe we should do so.
The best way to do this is to rewrite the definition of the header in a
parametric format. Such a rewrite is attached below. Alternatively a
minimal set of changes could be made; this might look more attractive but
makes the resulting text harder to understand. Such a set of changes was
included in PC-UK0053.
Proposed rewrite
================
[The affected areas are 7.8, 7.18, 7.26.4, and 7.26.8. These are
presented in reverse order for ease of appreciation. Rationale
comments are given in square brackets. Change bars show new or
modified text.]
7.26.8 Integer types <stdint.h>
[#1] Typedef names beginning with int or uint and ending with ||
_t may be added to the types defined in the <stdint.h>
header. Macro names beginning with INT or UINT and ending
with _MAX, _MIN, or _C may be added to the macros defined in the ||
<stdint.h> header.
[Note that at present the _C names aren't reserved. Also, the
term "type name" should have been "typedef name".]
7.26.4 Format conversion of integer types <inttypes.h>
[#1] Macro names beginning with PRI or SCN followed by any
lower case letter or X may be added to the macros defined in
the <inttypes.h> header.
7.18 Integer types <stdint.h>
[#1] The header <stdint.h> declares sets of integer types
having specified widths, and defines corresponding sets of
macros.200) It also defines macros that specify limits of
integer types corresponding to types defined in other
standard headers.
____________________
200See ``future library directions'' (7.26.8).
____________________
[#2] Types are defined in the following categories:
-- integer types having certain exact widths;
-- integer types having at least certain specified widths;
-- fastest integer types having at least certain specified
widths;
-- integer types wide enough to hold pointers to objects;
-- integer types having greatest width.
(Some of these types may denote the same type.)
[#3] Corresponding macros specify limits of the declared
types and construct suitable constants.
[#4] For each type described herein that the implementation ||
chooses to provide,201) <stdint.h> shall declare that typedef ||
name and the associated macros. Conversely, for each type ||
described herein that is not provided by the implementation, ||
<stdint.h> shall not define that typedef name nor the associated ||
macros. An implementation must provide those types described as ||
"required", but need not provide any of others (described as ||
"optional"). ||
____________________
201Some of these types may denote implementation-defined
extended integer types.
____________________
[Rationale: except for the required types, an implementation is
permitted to state that a given internal type is not an "integer
type" within the wording of the Standard. However, if so, the type
cannot be used for such types as size_t. It is not reasonable to
require all possible types, because otherwise this would require
all of [u]int_least1_t to [u]int_least64_t to be defined in every
implementation. However, those types required in CD2 are treated
specially, being required if they are available.]
7.18.1 Integer types
[#1] When typedef names differing only in the absence or ||
presence of the initial u are defined, they shall denote
corresponding signed and unsigned types as described in
6.2.5. Where one type of a pair is provided by an implementation ||
the other must also be. ||
[#2] The symbol /N/ represents an unsigned decimal integer with ||
no leading zeroes, such as 8 or 24 but not 04 or 048. ||
7.18.1.1 Exact-width integer types
[#1] The typedef name int/N/_t shall designate a signed integer ||
type with width N. Thus int8_t denotes a signed integer type ||
with a width of exactly 8 bits. ||
[#2] The typedef name uint/N/_t shall designate an unsigned ||
integer type with width N. Thus uint24_t denotes an usigned ||
integer type with a width of exactly 24 bits. ||
[#3] These types are optional. However, if the implementation ||
provides integer types with widths of 8, 16, 32, or 64, the ||
corresponding typedef names shall be defined. ||
7.18.1.2 Minimum-width integer types
[#1] The typedef name int_least/N/_t shall designate 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_t denotes a signed integer type that has a ||
width of at least 32 bits. ||
[#2] The typedef name uint_least/N/_t shall designate 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_t denotes an unsigned integer type that ||
has a width of at least 16 bits. ||
[#3] The following types are required: ||
int_least8_t int_least32_t
int_least16_t int_least64_t
uint_least8_t uint_least32_t
uint_least16_t uint_least64_t
All other types of this form are optional. ||
7.18.1.3 Fastest minimum-width integer types
[#1] Each of the following types designates an integer type
that is usually fastest202) to operate with among all
integer types that have at least the specified width.
____________________
202The designated type is not guaranteed to be fastest for
all purposes; if the implementation has no clear grounds
for choosing one type over another, it will simply pick
some integer type satisfying the signedness and width
requirements.
____________________
[#2] The typedef name int_fast/N/_t shall designate the ||
fastest signed integer type with a width of at least N. The ||
typedef name uint_fast/N/_t shall designate the fastest ||
unsigned integer type with a width of at least N. ||
[#3] The following types are required: ||
int_fast8_t int_fast32_t
int_fast16_t int_fast64_t
uint_fast8_t uint_fast32_t
uint_fast16_t uint_fast64_t
All other types of this form are optional. ||
7.18.1.4 Integer types capable of holding object pointers
[Left unchanged]
7.18.1.5 Greatest-width integer types
[Left unchanged]
7.18.2 Limits of specified-width integer types
[#1] The following object-like macros203) specify the
minimum and maximum limits of the types declared in
<stdint.h>. Each macro name corresponds to a similar type
name in 7.18.1.
____________________
203C++ implementations should define these macros only when
__STDC_LIMIT_MACROS is defined before <stdint.h> is
included.
____________________
[#2] Each instance of any defined macro shall be replaced by
a constant expression suitable for use in #if preprocessing
directives, and this expression shall have the same type as
would an expression that is an object of the corresponding
type converted according to the integer promotions. Its
implementation-defined value shall be equal to or greater in
magnitude (absolute value) than the corresponding value
given below, with the same sign, except where stated to be ||
exactly the given value. ||
[In the following, A^B means A superscript B.]
7.18.2.1 Limits of exact-width integer types
-- minimum values of exact-width signed integer types
INT/N/_MIN exactly either 1-2^(N-1) or -2^(N-1) ||
-- maximum values of exact-width signed integer types
INT/N/_MAX exactly 2^(N-1)-1 ||
-- maximum values of exact-width unsigned integer types
UINT/N/_MAX exactly 2^N-1 ||
7.18.2.2 Limits of minimum-width integer types
-- minimum values of minimum-width signed integer types
INT_LEAST/N/_MIN 1-2^(N-1) ||
-- maximum values of minimum-width signed integer types
INT_LEAST/N/_MAX 2^(N-1)-1 ||
-- maximum values of minimum-width unsigned integer types
UINT_LEAST/N/_MAX 2^N-1 ||
7.18.2.3 Limits of fastest minimum-width integer types
-- minimum values of fastest minimum-width signed integer
types
INT_FAST/N/_MIN 1-2^(N-1) ||
-- maximum values of fastest minimum-width signed integer
types
INT_FAST/N/_MAX 2^(N-1)-1 ||
-- maximum values of fastest minimum-width unsigned
integer types
UINT_FAST/N/_MAX 2^N-1 ||
7.18.2.4 Limits of integer types capable of holding object
pointers
[Left unchanged]
7.18.2.5 Limits of greatest-width integer types
[Left unchanged]
7.18.3 Limits of other integer types
[Left unchanged]
7.18.4 Macros for integer constants
[#1] The following function-like macros205) expand to
integer constants suitable for initializing objects that
have integer types corresponding to types defined in
<stdint.h>. Each macro name corresponds to a similar type
name in 7.18.1.2 or 7.18.1.5.
____________________
205C++ implementations should define these macros only when
__STDC_CONSTANT_MACROS is defined before <stdint.h> is
included.
____________________
[#2] The argument in any instance of these macros shall be a
decimal, octal, or hexadecimal constant (as defined in
6.4.4.1) with a value that does not exceed the limits for
the corresponding type.
7.18.4.1 Macros for minimum-width integer constants
[#1] Each of the following macros expands to an integer
constant having the value specified by its argument and a
type with at least the specified width.205a) ||
____________________
205a For each name described in 7.18.1.2 that is provided by ||
the implementation, the corresponding macro in this section ||
is required. ||
____________________
[#2] The macro INT/N/_C(value) shall expand to a signed ||
integer constant with the type int_least/N/_t. The macro ||
UINT/N/_C(value) shall expand to an unsigned integer constant ||
with the type uint_least/N/_t. For example, if uint_least64_t ||
is a name for the type unsigned long long, then UINT64_C(0x123) ||
might expand to the integer constant 0x123ULL. ||
7.18.4.2 Macros for greatest-width integer constants
[#1] The following macro expands to an integer constant
having the value specified by its argument and the type
intmax_t:
INTMAX_C(value)
The following macro expands to an integer constant having
the value specified by its argument and the type uintmax_t:
UINTMAX_C(value)
7.8 Format conversion of integer types <inttypes.h>
[#1] The header <inttypes.h> includes the header <stdint.h>
and extends it with additional facilities provided by hosted
implementations.
[#2] It declares four functions for converting numeric
character strings to greatest-width integers and, for each
type declared in <stdint.h>, it defines corresponding macros
for conversion specifiers for use with the formatted
input/output functions.169)
____________________
169See ``future library directions'' (7.26.4).
____________________
Forward references: integer types <stdint.h> (7.18).
7.8.1 Macros for format specifiers
[#1] Each of the following object-like macros170) expands to
a character string literal containing a conversion
specifier, possibly modified by a length modifier, suitable
for use within the format argument of a formatted
input/output function when converting the corresponding
integer type. These macro names have the general form of
PRI (character string literals for the fprintf family) or
SCN (character string literals for the fscanf family),171)
followed by the conversion specifier, followed by a name
corresponding to a similar type name in 7.18.1. In these ||
names, /N/ represents the width of the type as described in ||
7.18.1. For example, PRIdFAST32 can be used in a format string ||
to print the value of an integer of type int_fast32_t.
____________________
170C++ implementations should define these macros only when
__STDC_FORMAT_MACROS is defined before <inttypes.h> is
included.
171Separate macros are given for use with fprintf and fscanf
functions because, in the general case, different format
specifiers may be required for fprintf and fscanf, even
when the type is the same.
____________________
[#2] The fprintf macros for signed integers are:
PRId/N/ PRIdLEAST/N/ PRIdFAST/N/ PRIdMAX PRIdPTR ||
PRIi/N/ PRIiLEAST/N/ PRIiFAST/N/ PRIiMAX PRIiPTR ||
[#3] The fprintf macros for unsigned integers are:
PRIo/N/ PRIoLEAST/N/ PRIoFAST/N/ PRIoMAX PRIoPTR ||
PRIu/N/ PRIuLEAST/N/ PRIuFAST/N/ PRIuMAX PRIuPTR ||
PRIx/N/ PRIxLEAST/N/ PRIxFAST/N/ PRIxMAX PRIxPTR ||
PRIX/N/ PRIXLEAST/N/ PRIXFAST/N/ PRIXMAX PRIXPTR ||
[#4] The fscanf macros for signed integers are:
SCNd/N/ SCNdLEAST/N/ SCNdFAST/N/ SCNdMAX SCNdPTR ||
SCNi/N/ SCNiLEAST/N/ SCNiFAST/N/ SCNiMAX SCNiPTR ||
[#5] The fscanf macros for unsigned integers are:
SCNo/N/ SCNoLEAST/N/ SCNoFAST/N/ SCNoMAX SCNoPTR ||
SCNu/N/ SCNuLEAST/N/ SCNuFAST/N/ SCNuMAX SCNuPTR ||
SCNx/N/ SCNxLEAST/N/ SCNxFAST/N/ SCNxMAX SCNxPTR ||
[#6] For each type that the implementation provides in the ||
<stdint.h> header, the corresponding PRI macros must be defined; ||
the corresponding SCN macros must be defined unless the ||
implementation does not have suitable fscanf length modifiers ||
for arguments that are pointers to those types. ||
[#7] EXAMPLE
#include <inttypes.h>
#include <wchar.h>
int main(void)
{
uintmax_t i = UINTMAX_MAX; // this type always exists
wprintf(L"The largest integer value is %020"
PRIxMAX "\n", i);
return 0;
}
7.8.2 Conversion functions for greatest-width integer types
[Left unchanged]