SC22/WG14/N851 Changes to and Clive Feather clive@demon.net 1998-09-22 [All references in this paper are to CD2.] Summary ======= The headers and 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 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 [#1] Typedef names beginning with int or uint and ending with || _t may be added to the types defined in the header. Macro names beginning with INT or UINT and ending with _MAX, _MIN, or _C may be added to the macros defined in the || 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 [#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 header. 7.18 Integer types [#1] The header 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) shall declare that typedef || name and the associated macros. Conversely, for each type || described herein that is not provided by the implementation, || 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 . 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 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 . 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 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 [#1] The header includes the header 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 , 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 (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 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 || 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 #include 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]