https://gcc.gnu.org/bugzilla/show_bug.cgi?id=90081
Bug ID: 90081
Summary: stdint constant macros evaluating to wrong type
Product: gcc
Version: 8.3.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: c
Assignee: unassigned at gcc dot gnu.org
Reporter: bafap5 at yahoo dot com
Target Milestone: ---
stdint.h defines macros for expressing integer constant expressions in such a
way that they evaluate to given types. In the stdint.h spec:
"The macro INTN_C( value) shall expand to an integer constant expression
corresponding to the type int_least N _t. The macro UINTN_C( value) shall
expand to an integer constant expression corresponding to the type uint_least N
_t."
However, within the current version of stdint.h, I find the following:
/* Signed. */
# define INT8_C(c) c
# define INT16_C(c) c
# define INT32_C(c) c
# if __WORDSIZE == 64
# define INT64_C(c) c ## L
# else
# define INT64_C(c) c ## LL
# endif
/* Unsigned. */
# define UINT8_C(c) c
# define UINT16_C(c) c
# define UINT32_C(c) c ## U
# if __WORDSIZE == 64
# define UINT64_C(c) c ## UL
# else
# define UINT64_C(c) c ## ULL
# endif
Many of these macros aren't actually transforming the input at all, which leads
to some erroneous results at compile-time. This was first brought to my
attention in a situation similar to the following:
int32_t x = -5;
if (x < INT32_C(0xFFFFFFFF))
Upon compiling with -Wall -Wextra, the following warning is generated:
warning: comparison of integer expressions of different signedness: ‘int32_t’
{aka ‘int’} and ‘unsigned int’ [-Wsign-compare]
if (x < INT32_C(0xFFFFFFFF))
^
In this way, stdint.h violates the spec, as it is supposed to explicitly yield
a signed expression. I was able to work around this issue by using a cast, but
the macro is really what I'd rather be using.
Inspection of the actual macro definitions reveals the potential for further
errors, such as the following:
int x = (uint8_t) -5; /* Correct, gives 251 */
int y = UINT8_C(-5); /* Incorrect, gives -5 */
The suggested resolution is to adjust the macros to always cast to the
appropriate "_leastN_t" types as the spec requires. Even in cases where the
default type for an expression would be large enough for the given value (such
as int8_t being stored in an int), the spec nonetheless requires the
"_leastN_t" type, which becomes meaningful in the context of dereferencing
operations.
I don't know exactly how gcc is currently deciding on which type to use for a
given integer literal, so I don't want to post a suggestion that could
potentially cause problems... But as far as I can tell, putting explicit casts
in all of the macros should fix the problem.