左移和右移运算符: <<>>

按位移位运算符是右移运算符(>>),它将整数或枚举类型表达式的位向右移动,左移运算符(<<)将位移到左侧。 1

语法

shift-expression:
additive-expression
shift-expression << additive-expression
shift-expression >> additive-expression

注解

重要

对于 x86 和 x64 体系结构,以下说明和示例在 Windows 上有效。 对于 ARM 设备,在 Windows 上,左移和右移运算符的实现明显不同。 有关详细信息,请参阅 Hello ARM 博客文章的“Shift 运算符”部分。

左移

左移运算符使位 shift-expression 按指定的 additive-expression位置数向左移。 移位作已空出的位位置是零填充的。 左移是一个逻辑移位(从末尾移出位的位将被丢弃,包括符号位)。 有关按位移位类型的详细信息,请参阅 按位移位。

以下示例显示使用无符号数字的左移作。 该示例通过将值表示为位集来显示位点发生的情况。 有关详细信息,请参阅 bitset 类

#include <iostream>
#include <bitset>

using namespace std;

int main() {
    unsigned short short1 = 4;
    bitset<16> bitset1{short1};   // the bitset representation of 4
    cout << bitset1 << endl;  // 0b00000000'00000100

    unsigned short short2 = short1 << 1;     // 4 left-shifted by 1 = 8
    bitset<16> bitset2{short2};
    cout << bitset2 << endl;  // 0b00000000'00001000

    unsigned short short3 = short1 << 2;     // 4 left-shifted by 2 = 16
    bitset<16> bitset3{short3};
    cout << bitset3 << endl;  // 0b00000000'00010000
}

如果向左移一个有符号号码,使签名位受到影响,则结果未定义。 以下示例演示在将 1 位左移到符号位位置时会发生什么情况。

#include <iostream>
#include <bitset>

using namespace std;

int main() {
    short short1 = 16384;
    bitset<16> bitset1(short1);
    cout << bitset1 << endl;  // 0b01000000'00000000

    short short3 = short1 << 1;
    bitset<16> bitset3(short3);  // 16384 left-shifted by 1 = -32768
    cout << bitset3 << endl;  // 0b10000000'00000000

    short short4 = short1 << 14;
    bitset<16> bitset4(short4);  // 4 left-shifted by 14 = 0
    cout << bitset4 << endl;  // 0b00000000'00000000
}

右移

右移运算符使位模式 shift-expression 按指定 additive-expression的位置数向右移动。 对于无符号数字,移位作已空出的位位置是零填充的。 对于带符号数字,符号位用于填充空位位置。 换句话说,如果数字为正数,则使用 0,如果数字为负数,则使用 1。

重要

有符号负数右移的结果取决于实现。 尽管Microsoft C++编译器使用符号位来填充空位位置,但不能保证其他实现也这样做。

此示例显示使用无符号号码的右移作:

#include <iostream>
#include <bitset>

using namespace std;

int main() {
    unsigned short short11 = 1024;
    bitset<16> bitset11{short11};
    cout << bitset11 << endl;     // 0b00000100'00000000

    unsigned short short12 = short11 >> 1;  // 512
    bitset<16> bitset12{short12};
    cout << bitset12 << endl;     // 0b00000010'00000000

    unsigned short short13 = short11 >> 10;  // 1
    bitset<16> bitset13{short13};
    cout << bitset13 << endl;     // 0b00000000'00000001

    unsigned short short14 = short11 >> 11;  // 0
    bitset<16> bitset14{short14};
    cout << bitset14 << endl;     // 0b00000000'00000000
}

下一个示例显示带正符号数字的右移作。

#include <iostream>
#include <bitset>

using namespace std;

int main() {
    short short1 = 1024;
    bitset<16> bitset1(short1);
    cout << bitset1 << endl;     // 0b00000100'00000000

    short short2 = short1 >> 1;  // 512
    bitset<16> bitset2(short2);
    cout << bitset2 << endl;     // 0b00000010'00000000

    short short3 = short1 >> 11;  // 0
    bitset<16> bitset3(short3);
    cout << bitset3 << endl;     // 0b00000000'00000000
}

下一个示例显示带负带符号整数的右移作。

#include <iostream>
#include <bitset>

using namespace std;

int main() {
    short neg1 = -16;
    bitset<16> bn1(neg1);
    cout << bn1 << endl;  // 0b11111111'11110000

    short neg2 = neg1 >> 1; // -8
    bitset<16> bn2(neg2);
    cout << bn2 << endl;  // 0b11111111'11111000

    short neg3 = neg1 >> 2; // -4
    bitset<16> bn3(neg3);
    cout << bn3 << endl;  // 0b11111111'11111100

    short neg4 = neg1 >> 4; // -1
    bitset<16> bn4(neg4);
    cout << bn4 << endl;  // 0b11111111'11111111

    short neg5 = neg1 >> 5; // -1
    bitset<16> bn5(neg5);
    cout << bn5 << endl;  // 0b11111111'11111111
}

班次和促销

Shift 运算符两侧的表达式必须是整型类型。 积分提升是根据 标准转换中所述的规则执行的。 结果的类型与提升 shift-expression的类型相同。

在下面的示例中,类型char变量提升为 .int

#include <iostream>
#include <typeinfo>

using namespace std;

int main() {
    char char1 = 'a';

    auto promoted1 = char1 << 1;   // 194
    cout << typeid(promoted1).name() << endl;  // int

    auto promoted2 = char1 << 10;  // 99328
    cout << typeid(promoted2).name() << endl;  // int
}

详细信息

如果为负数或additive-expression大于或等于 (提升) shift-expression中的位数,则未定义additive-expression班次运算的结果。 如果 additive-expression 为 0,则不执行 Shift作。

#include <iostream>
#include <bitset>

using namespace std;

int main() {
    unsigned int int1 = 4;
    bitset<32> b1{int1};
    cout << b1 << endl;    // 0b00000000'00000000'00000000'00000100

    unsigned int int2 = int1 << -3;  // C4293: '<<' : shift count negative or too big, undefined behavior
    unsigned int int3 = int1 >> -3;  // C4293: '>>' : shift count negative or too big, undefined behavior
    unsigned int int4 = int1 << 32;  // C4293: '<<' : shift count negative or too big, undefined behavior
    unsigned int int5 = int1 >> 32;  // C4293: '>>' : shift count negative or too big, undefined behavior
    unsigned int int6 = int1 << 0;
    bitset<32> b6{int6};
    cout << b6 << endl;    // 0b00000000'00000000'00000000'00000100 (no change)
}

Footnotes

1 以下是 C++11 ISO 规范(INCITS/ISO/IEC 14882-2011[2012])中的班次运算符的说明,第 5.8.2 节和 5.8.3 节。

左移E2位位置的值E1 << E2E1;空置位为零填充。 如果 E1 具有无符号类型,则结果的值为 E1 × 2E2,将模数减少一个大于结果类型中可表示的最大值。 否则,如果 E1 具有有符号类型和非负值,并且 E1 × 2E2 在结果类型的相应无符号类型中表示,则该值转换为结果类型是结果值;否则,行为是未定义的。

E1 >> E2 E1值为右移E2位位置。 如果 E1 具有无符号类型或者 E1 具有有符号类型和非负值,则结果的值是 E1/2E2 商的整部分。 如果 E1 具有有符号类型和负值,则生成的值为实现定义。

另请参阅

具有二进制运算符的表达式
C++内置运算符、优先级和关联性