Consider the following listing:
#include <type_traits>
#include <cstdint>
static_assert(std::is_same_v<decltype(31), int32_t>);
static_assert(std::is_same_v<decltype(31u), uint32_t>);
static_assert(std::is_same_v<decltype((signed char)1 << 1), int32_t>);
static_assert(std::is_same_v<decltype((signed char)1 << 1u), int32_t>);
static_assert(std::is_same_v<decltype((unsigned char)1 << 1), int32_t>);
// Signed result for unsigned char
static_assert(std::is_same_v<decltype((unsigned char)1 << 1u), int32_t>);
// But unsigned for uint32_t
static_assert(std::is_same_v<decltype(1u << 1u), uint32_t>);
It compiles fine with GCC and Clang. I am quite confused about operator<<(uint8_t, uint32_t)
. Why the result is signed?
Per [expr.shift]
The operands shall be of integral or unscoped enumeration type and integral promotions are performed. The type of the result is that of the promoted left operand. [...]
So for unsigned char
and int
, the left operand is promoted from unsigned char
to int
1 (see [conv.prom]), and the result type is the one of the promoted left operand, so int
.
1 At least on most common platforms (where sizeof(char) < sizeof(int)
), otherwise it might get promoted to unsigned int
if sizeof(char) == sizeof(int)
.
For the <<
operator, the left operand is promoted with the integral promotions. There are some technical details in the integral promotions, but largely they are: Types narrower than int
are promoted to int
. Other integer types are unchanged.
The result type of the <<
operator is the type of its left operand after promotion.
In your examples, (signed char)1
and (unsigned char)1
are narrower than int
, so they are promoted to int
, which is equivalent to int32_t
in your C++ implementation. 31
is an int
, so it remains int
. 31u
and 1u
are unsigned int
, so they remain unsigned int
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With