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];
Created attachment 1121 [details] UINT8_C and UINT16_C should not append U
The specificaiton is broken one way or another so I don't really care. The patch is in cvs.
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.
UINTC_8(-1) is undefined.
(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.
(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.