Why do implementations of "stdint.h" disagree on the definition of UINT8_C?
The first two implementations are not conforming to the C standard, because they don't permit UINT8_C(42)
in #if
directives:
#if UINT8_C(42) == 42 // <- should be a valid expression
N1570 7.20.4/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 an int
can represent all the values of a uint_least8_t
then the GNU implementation of the UINT8_C(value)
macro as #define UINT8_C(c) c
conforms to the C standard.
As per C11 7.20.4 Macros for integer constants paragraph 2:
The argument in any instance of these macros shall be an unsuffixed integer constant (as defined in 6.4.4.1) with a value that does not exceed the limits for the corresponding type.
For example, if UINT_LEAST8_MAX
is 255, the following usage examples are legal:
UINT8_C(0)
UINT8_C(255)
UINT8_C(0377)
UINT8_C(0xff)
But the following usage examples result in undefined behavior:
UINT8_C(-1)
— not an integer constant as defined in 6.4.4.1UINT8_C(1u)
— not an unsuffixed integer constantUINT8_C(256)
— exceeds the limits ofuint_least8_t
for this implementation
The signed equivalent INT8_C(-1)
is also undefined behavior for the same reasons.
If UINT_LEAST8_MAX
is 255, a legal instance of UINT8_C(value)
will expand to an integer constant expression and its type will be int
due to integer promotions, as per paragraph 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.
Thus for any legal invocation of UINT8_C(value)
, the expansion of this to value
by any implementation where an int
can represent all the values of uint_least8_t
is perfectly standard conforming. For any illegal invocation of UINT8_C(value)
you may not get the result you were expecting due to undefined behavior.
[EDIT added for completeness] As pointed out in cpplearner's answer, the other implementations of UINT8_C(value)
shown in OP's question are invalid because they expand to expressions that are not suitable for use in #if
processing directives.
The GNU C library is not correct. Per C11 7.20.4.1 Macros for minimum-width integer constants UINTN_C(value)
is defined as
The macro
UINTN_C(value)
shall expand to an integer constant expression corresponding to the typeuint_leastN_t
.
So it is not proper the they just use c
since c
may or may not be a uint_least8_t
.