For uint32_t
and uint64_t
results are expected, but promotions for uint8_t
and uint16_t
are strange. Tests on c++14/c++17, gcc and clang, 64-bit linux, sizeof(int) == 4
.
#include <cstdint>
using namespace std;
static_assert( uint8_t(-1)*uint8_t(-1) == 0xfe01); // OK, but why not 1?
static_assert( uint8_t(-1)*uint8_t(-1) == 1); // error: static assertion failed
static_assert( uint16_t(-1)*uint16_t(-1) == 1); // error: static_assert expression is not an integral constant expression
static_assert( uint32_t(-1)*uint32_t(-1) == 1); // OK
static_assert( uint64_t(-1)*uint64_t(-1) == 1); // OK
Is in the following case std::uint16_t
promoted to int?
static_assert( uint16_t(-1)*uint16_t(-1) == uint16_t(uint16_t(-1)*uint16_t(-1)));
The compiler messages are:
error: static_assert expression is not an integral constant expression
static_assert( uint16_t(-1)*uint16_t(-1) == uint16_t(uint16_t(-1)*uint16_t(-1)));
note: value 4294836225 is outside the range of representable values of type 'int'
static_assert( uint16_t(-1)*uint16_t(-1) == uint16_t(uint16_t(-1)*uint16_t(-1)));
More interestingly the same assert for std::uint8_t
is correct, but fails:
static_assert( uint8_t(-1)*uint8_t(-1) == uint8_t(uint8_t(-1)*uint8_t(-1))); //error: static_assert failed
static_assert( uint8_t(-1)*uint8_t(-1) == 0xfe01); // does not fail
So it looks like uint8_t
is promoted to uint16_t
, but uint16_t
is promoted to signed int
. uint32_t
is not promoted uint64_t
.
Anyone can tell me why these promotions are done, is it specified in standard, or can differ on different implementations?