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.1
  • UINT8_C(1u) — not an unsuffixed integer constant
  • UINT8_C(256) — exceeds the limits of uint_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 type uint_leastN_t.

So it is not proper the they just use c since c may or may not be a uint_least8_t.