[英]Bit shift leads to strange type conversion
The following code compiles without warning: 以下代码在没有警告的情况下编译:
std::uint16_t a = 12;
std::uint16_t b = a & 0x003f;
However, performing a bit shift along with the bitwise and leads to an 'implicit cast warning': 但是,与按位一起执行位移并导致“隐式强制警告”:
std::uint16_t b = (a & 0x003f) << 10; // Warning generated.
Both gcc and clang complain that there is an implicit conversion from int
to uint16_t
, yet I fail to see why introducing the bit shift would cause the right hand expression to suddenly evaluate to an int
. gcc和clang都抱怨存在从
int
到uint16_t
的隐式转换,但我不明白为什么引入位移会导致右手表达式突然计算为int
。
EDIT: For clang, I compiled with the -std=c++14 -Weverything
flags; 编辑:对于clang,我使用
-std=c++14 -Weverything
标志进行编译; for gcc, I compiled with the -std=c++14 -Wall -Wconversion
flags. 对于gcc,我使用
-std=c++14 -Wall -Wconversion
标志编译。
Doing any arithmetic with integer types always is preceded by promotion to at least (sometimes, but not in this case using gcc, unsigned
) int
. 使用整数类型执行任何算术总是在促销之前至少(有时,但在这种情况下不使用gcc,
unsigned
) int
。 As you can see by this example , this applies to you first, warning-less variant too. 正如您在此示例中所看到的,这首先适用于您,也适用于无警告变体。
The probably best way to get around these (admittedly often surprising) integer promotion rules would be to use an unsigned int
(or uint32_t
on common platforms) from the get go. 解决这些(通常是令人惊讶的)整数提升规则的最好方法是在get go中使用
unsigned int
(或常见平台上的uint32_t
)。
If you cannot or don't want to use the bigger type, you can just static_cast
the result of the whole expression back to std::uint16_t
: 如果你不能或不想使用更大的类型,你可以将整个表达式的
static_cast
回到std::uint16_t
:
std::uint16_t b = static_cast<std::uint16_t>((a & 0x003f) << 10);
This will correctly result in the RHS-value mod 2^16. 这将正确地导致RHS值mod 2 ^ 16。
yet I fail to see why introducing the bit shift would cause the right hand expression to suddenly evaluate to an int.
但我没有看到为什么引入位移会导致右手表达式突然计算为int。
I think you misinterpret the warning. 我想你误解了这个警告。 In both cases expression evaluate to
int
but in the first case result will always fit in uint16_t
, in the second case it will not. 在这两种情况下,表达式求值为
int
但在第一种情况下,结果总是适合uint16_t
,在第二种情况下,它不会。 Looks like the compiler is smart enough to detect that and generates warning only in the second case. 看起来编译器足够智能以检测它并仅在第二种情况下生成警告。
From cppreference.com : "If the operand passed to an arithmetic operator is integral or unscoped enumeration type, then before any other action (but after lvalue-to-rvalue conversion, if applicable), the operand undergoes integral promotion ." 来自cppreference.com : “如果传递给算术运算符的操作数是整数或无范围枚举类型,那么在任何其他操作之前(但在左值到右值转换之后,如果适用),操作数将进行整数提升 。”
For instance: 例如:
byte a = 1;
byte b = a << byte(1);
a
and 1
are promoted to int
: int(a)
and int(byte(1))
. a
和1
被提升为int
: int(a)
和int(byte(1))
。 a
is shifted one position to left: int result = int(a) << int(byte(1))
(the result is an int
). a
向左移动一个位置: int result = int(a) << int(byte(1))
(结果为int
)。 result
is stored in b
. result
存储在b
。 Since int
is wider than byte
an warning will be issued. int
比byte
宽,因此将发出警告。 If the operands are constant expressions , a compiler might be able to compute the result at compile time and issue an warning iff the result does not fit in destination: 如果操作数是常量表达式 ,则编译器可能能够在编译时计算结果,并在结果不适合目标时发出警告:
byte b = 1 << 1; // no warning: does not exceed 8 bits
byte b = 1 << 8; // warning: exceeds 8 bits
Or, using constexpr
: 或者,使用
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
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.