以下代码在没有警告的情况下编译:
std::uint16_t a = 12;
std::uint16_t b = a & 0x003f;
但是,按位进行位移会导致“隐式强制警告”:
std::uint16_t b = (a & 0x003f) << 10; // Warning generated.
gcc和clang都抱怨存在从int
到uint16_t
的隐式转换,但我不明白为什么引入位移会导致右手表达式突然计算为{{{ 1}}。
int
标志编译;对于gcc,我使用-std=c++14 -Weverything
标志编译。
答案 0 :(得分:2)
使用整数类型进行任何算术之前,至少会进行升级(有时,但不是在这种情况下使用gcc,unsigned
)int
。正如您在this example所看到的那样,这首先适用于您,也适用于无警告变体。
解决这些(通常是令人惊讶的)整数提升规则的最佳方法是在开始时使用unsigned int
(或uint32_t
在常用平台上)。
如果您不能或不想使用较大的类型,则可以static_cast
将整个表达式的结果返回std::uint16_t
:
std::uint16_t b = static_cast<std::uint16_t>((a & 0x003f) << 10);
这将正确地导致RHS值mod 2 ^ 16。
答案 1 :(得分:1)
但是我没有看到为什么引入位移会导致右手表达式突然评估为int。
我认为你误解了这个警告。在这两种情况下,表达式评估为int
,但在第一种情况下,结果将始终适合uint16_t
,而在第二种情况下,结果将不适合import os
os.system('cls||clear')
。看起来编译器足够智能以检测它并仅在第二种情况下生成警告。
答案 2 :(得分:1)
从cppreference.com:&#34;如果传递给算术运算符的操作数是整数或无范围枚举类型,则在任何其他操作之前(但在左值到右值转换后,如果适用) ,操作数经历整体推广。&#34;
例如:
byte a = 1;
byte b = a << byte(1);
a
和1
被提升为int
:int(a)
和int(byte(1))
。a
向左移动一个位置:int result = int(a) << int(byte(1))
(结果为int
)。result
存储在b
中。由于int
比byte
更宽,因此会发出警告。如果操作数是常量表达式,编译器可能能够在编译时计算结果,并在结果不适合目标时发出警告:
byte b = 1 << 1; // no warning: does not exceed 8 bits
byte b = 1 << 8; // warning: exceeds 8 bits
或者,使用constexpr
:
constexpr byte a = 1;
byte b = a << 1; // no warning: it fits in 8 bits
byte b = a << 8; // warning: it does not fit in 8 bits