Few programmers consider the issues around formatted I/O and typedefstype definitions. A programmer-defined integer type might be any type supported by the implementation, even a type larger than unsigned long long
.
For example, given an implementation that supports 128-bit unsigned integers and provides a uint_fast128_t
type for them would allow a programmar to use thema programmer may define the following type:
Code Block |
---|
typedef uint_fast128_t mytypedef_t; |
...
The C99 intmax_t
and uintmax_t
types are capable of representing any value representable by any other integer types of the same signedness (see INT00-A. Understand the data model used by your implementation(s)). This allows conversion between programmer-defined integer types (of the same signedness) and intmax_t
and uintmax_t
. For example:
Code Block |
---|
mytypedef_t x; uintmax_t temp; /* ... */ temp = x; /* always safe */ /* ... change the value of temp ... */ if (temp <= MYTYPEDEF_MAX) { x = temp; } |
Formatted I/O functions can be used to input and output functions contain a length modifier which provides the above facilities for input/outputgreatest-width integer typed values. The j
length modifier in a format string indicates that the following d
, i
, o
, u
, x
, X
, or n
conversion specifier will apply to an argument with type intmax_t
or uintmax_t
. C99 also specifies the z
length modifier for use with arguments of type size_t
, and the t
length modifier for arguments of type ptrdiff_t
.
This rule is closely related to INT00-A. Understand the data model used by your implementation(s)In addition to programmer-defined types, there is no requirement that an implementation provides format length modifiers for implementation-defined integer types. For example, a machine with an implementation-defined 48-bit integer type may not provide format length modifiers for the type. Such a machine would still have to have a 64-bit long long
, with intmax_t
being at least that large.
Non-Compliant Code Example (printf()
)
The following This non-compliant code example prints the value of x
, whose type is as an unsigned long long
value, even though the value is of a programmer-defined integer type.
Code Block | ||
---|---|---|
| ||
#include <stdio.h> /* ... */ mytypedef_t x; /* ... */ printf("%llu", (unsigned long long) x); |
HoweverConsequently, there is no guarantee that this code prints the correct value of x
, as x
is not necessarily typed as an unsigned long long
value and may have a value be too large to represent as an unsigned long long
.
...
The C99 intmax_t
and uintmax_t
can be safely be used to perform formatted I/O with programmer-defined integer types. Convert This is accomplished by converting signed programmer-defined integer types to intmax_t
and unsigned programmer-defined integer types to uintmax_t
, then output outputting these values using the j
length modifier. Similarly, input programmer-defined integer types into can be input to variables of intmax_t
or uintmax_t
(whichever matches the signedness of the programmer-defined integer type) and then convert converted to the programmer-defined integer types using appropriate range checks.
...
Code Block | ||
---|---|---|
| ||
#include <stdio.h> #include <inttypes.h> /* ... */ mytypedef_t x; /* ... */ printf("%ju", (uintmax_t) x); |
There is no requirement that an implementation provides format length modifiers for implementation-defined integer types. For example, a machine with an implementation-defined 48-bit integer type might not bother to provide format length modifiers for the type. Such a machine would still have to have a 64-bit long long
, with intmax_t
being at least that large. So, this solution can be applied even if there are no format length modifiers for the 48-bit integers.
Non-Compliant Code Example (scanf()
)
The following non-compliant code example reads data am unsigned long long
value from standard input into and stores the result in x
, which is of a programmer-defined integer type.
Code Block | ||
---|---|---|
| ||
#include <stdio.h> /* ... */ mytypedef_t x; /* ... */ if(scanf("%llu", &x) != 1) { /* handle error */ } |
HoweverResultantly, this code could result in a buffer overflow, if the size of mytypedef_t
is smaller than unsigned long long
, or it may result in an incorrect value if the size of mytypedef_t
is larger than unsigned long long
.
...