位移导致奇怪的类型转换

时间:2016-04-29 14:01:09

标签: c++ type-conversion bit-shift

以下代码在没有警告的情况下编译:

std::uint16_t a = 12;
std::uint16_t b = a & 0x003f;

但是,按位进行位移会导致“隐式强制警告”:

std::uint16_t b = (a & 0x003f) << 10; // Warning generated.

gcc和clang都抱怨存在从intuint16_t的隐式转换,但我不明白为什么引入位移会导致右手表达式突然计算为{{{ 1}}。

编辑:对于clang,我使用int标志编译;对于gcc,我使用-std=c++14 -Weverything标志编译。

3 个答案:

答案 0 :(得分:2)

使用整数类型进行任何算术之前,至少会进行升级(有时,但不是在这种情况下使用gcc,unsignedint。正如您在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);
  1. a1被提升为intint(a)int(byte(1))
  2. a向左移动一个位置:int result = int(a) << int(byte(1))(结果为int)。
  3. result存储在b中。由于intbyte更宽,因此会发出警告。
  4. 如果操作数是常量表达式,编译器可能能够在编译时计算结果,并在结果不适合目标时发出警告:

    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