Bug 2841

Summary: stdint.h misdefines UINT8_C and UINT16_C to append U
Product: glibc Reporter: Paul Eggert <eggert>
Component: libcAssignee: Ulrich Drepper <drepper.fsp>
Status: RESOLVED FIXED    
Severity: normal CC: clement.pit, glibc-bugs
Priority: P2 Flags: fweimer: security-
Version: 2.4   
Target Milestone: ---   
Host: Target:
Build: Last reconfirmed:
Attachments: UINT8_C and UINT16_C should not append U

Description Paul Eggert 2006-06-24 06:35:40 UTC
C99 7.18.4.1 (as revised by ISO/IEC 9899:1999/Cor.1:2001) says that
UINT8_C and UINT16_C return values corresponding to uint_least8_t and
uint_least16_t.  They therefore must promote the same way.  But glibc
appends 'U', which causes UINT8_C and UINT16_C to promote to 'unsigned
int', not 'int'.  Here is a test program illustrating the bug: it
strictly conforms to the C99 but GCC + glibc reject it.  I'll attach
the obvious patch.

#include <stdint.h>
char test1[(-1 < UINT8_C (0)) == (-1 < (uint_least8_t) 0) ? 1 : -1];
char test2[(-1 < UINT16_C (0)) == (-1 < (uint_least16_t) 0) ? 1 : -1];
Comment 1 Paul Eggert 2006-06-24 06:36:20 UTC
Created attachment 1121 [details]
UINT8_C and UINT16_C should not append U
Comment 2 Ulrich Drepper 2006-08-12 21:23:18 UTC
The specificaiton is broken one way or another so I don't really care.  The
patch is in cvs.
Comment 3 Clément 2019-08-08 18:19:57 UTC
Paul, wouldn't it be better to also include a cast to uint_least8_t in that macro (that's what other libcs do, AFAICT)?  Right now UINTC_8(-1) produces an negative int, which is rather surprising.
Comment 4 Andreas Schwab 2019-08-08 18:47:07 UTC
UINTC_8(-1) is undefined.
Comment 5 Florian Weimer 2019-08-08 18:51:09 UTC
(In reply to Clément from comment #3)
> Paul, wouldn't it be better to also include a cast to uint_least8_t in that
> macro (that's what other libcs do, AFAICT)?  Right now UINTC_8(-1) produces
> an negative int, which is rather surprising.

I think the cast would be incorrect according to C11 because the “type of the expression shall have the same type as would an expression of the corresponding type converted according to the integer promotions.”  I think a definition like

  #define UINTC_8(c) ((uint_least_8_t) +(c))

wouldn't satisfy the requirement.  (The + is needed so that the expression can be used in an #if preprocessor context, as required.)

musl and bionic have the same definition as glibc.  The FreeBSD definition adds parentheses, but still has no cast.
Comment 6 Clément 2019-08-08 22:31:14 UTC
(In reply to Florian Weimer from comment #5)
> I think the cast would be incorrect according to C11 because the “type of
> the expression shall have the same type as would an expression of the
> corresponding type converted according to the integer promotions.”  I think
> a definition like
> 
>   #define UINTC_8(c) ((uint_least_8_t) +(c))
> 
> wouldn't satisfy the requirement.  (The + is needed so that the expression
> can be used in an #if preprocessor context, as required.)

Interesting, thanks a lot. I had checked AVR-libc and QP/C++, which use ((uint8_t) __CONCAT(value, U)) and (static_cast<std::uint8_t>(x_)) respectively.