ISO/ IEC 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]