移位运算符的结果类型是什么?

iva*_*ult 22 c++ types bit-shift integer-promotion

考虑以下清单:

#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>);
Run Code Online (Sandbox Code Playgroud)

它可以与 GCC 和 Clang 很好地编译。我很困惑operator<<(uint8_t, uint32_t)。为什么要签署结果?

Hol*_*olt 29

[expr.shift]

操作数应为整型或无作用域枚举类型,并执行整型提升。结果的类型是提升后的左操作数的类型。[...]

因此,对于unsigned charint,左操作数从 1 提升unsigned charint1(请参阅[conv.prom]),并且结果类型是提升后的左操作数之一,因此int


1至少在最常见的平台上(其中sizeof(char) < sizeof(int)),否则它可能会被提升为unsigned intif sizeof(char) == sizeof(int)


Eri*_*hil 14

对于<<运算符来说,左操作数通过积分提升来提升。积分提升中有一些技术细节,但主要是: 类型比int提升到的范围更窄int。其他整数类型不变。

运算符的结果类型<<是提升后其左操作数的类型。

在您的示例中,(signed char)1(unsigned char)1比 更窄int,因此它们被提升为int,这相当于int32_t您的 C++ 实现中的情况。31是一个int,所以它仍然存在int31u1uunsigned int所以它们仍然存在unsigned int