移位

一、移位运算符的概念

C++ 中有两个移位运算符:左移运算符 << 和右移运算符 >>。它们都是二元运算符。

移位运算符左边的操作数是需要移位的值,右边的操作数是移位的位数。

二、左移运算

左移运算将一个数的二进制位向左移动指定的位数。左移后,低位补 0,移出的高位舍弃。

形式:操作数 << 位数

示例:5 << 2

5 的二进制表示为 00000101,左移 2 位后变为 00010100,即十进制的 20。

左移 n 位相当于将原数乘以 2 的 n 次方(在不溢出的情况下)。

三、右移运算

右移运算将一个数的二进制位向右移动指定的位数。右移后,移出的低位舍弃。

对于高位补什么值,取决于操作数的类型:

无符号数:高位补 0。

有符号数:高位补符号位(正数补 0,负数补 1),具体行为依赖于编译器和处理器架构,但大多数系统采用算术右移(补符号位)。

形式:操作数 >> 位数

示例:20 >> 2

20 的二进制表示为 00010100,右移 2 位后变为 00000101,即十进制的 5。

右移 n 位相当于将原数除以 2 的 n 次方(向下取整)。

四、移位运算的示意图

以下用示意图说明移位过程:

左移示意图(以 unsigned char 为例):

原始值: 0 0 0 0 0 1 0 1 (十进制 5)

左移 2 位:0 0 0 1 0 1 0 0 (十进制 20)

低位补 0,高位移出舍弃。

右移示意图(以 unsigned char 为例):

原始值: 0 0 0 1 0 1 0 0 (十进制 20)

右移 2 位:0 0 0 0 0 1 0 1 (十进制 5)

高位补 0,低位移出舍弃。

有符号数右移示意图(以 char 为例,假设为补码表示):

原始值: 1 1 1 1 1 0 1 1 (十进制 -5)

右移 2 位:1 1 1 1 1 1 1 0 (十进制 -2)

高位补符号位 1,低位移出舍弃。

五、代码示例

以下代码演示了移位运算的实际应用:

#include <iostream>
using namespace std;

int main()
{
    // 左移示例
    unsigned int a = 5;
    cout << "a = " << a << endl;           // 输出 5
    cout << "a << 1 = " << (a << 1) << endl; // 输出 10
    cout << "a << 2 = " << (a << 2) << endl; // 输出 20

    // 右移示例(无符号数)
    unsigned int b = 20;
    cout << "b = " << b << endl;           // 输出 20
    cout << "b >> 1 = " << (b >> 1) << endl; // 输出 10
    cout << "b >> 2 = " << (b >> 2) << endl; // 输出 5

    // 右移示例(有符号数)
    int c = -20;
    cout << "c = " << c << endl;           // 输出 -20
    cout << "c >> 1 = " << (c >> 1) << endl; // 输出 -10(算术右移)
    cout << "c >> 2 = " << (c >> 2) << endl; // 输出 -5

    // 移位与赋值复合
    int x = 3;
    x <<= 2;    // 等价于 x = x << 2
    cout << "x after <<= 2 : " << x << endl; // 输出 12

    // 用移位实现乘除法
    int value = 10;
    int mul = value << 3;   // 乘以 8
    int div = value >> 1;   // 除以 2
    cout << "value * 8 = " << mul << endl;  // 输出 80
    cout << "value / 2 = " << div << endl;  // 输出 5

    // 从整数中提取特定字节
    int num = 0x12345678;
    unsigned char byte1 = (num >> 0) & 0xff;  // 最低字节
    unsigned char byte2 = (num >> 8) & 0xff;
    unsigned char byte3 = (num >> 16) & 0xff;
    unsigned char byte4 = (num >> 24) & 0xff; // 最高字节
    cout << "bytes: " << hex << (int)byte1 << " "
         << (int)byte2 << " "
         << (int)byte3 << " "
         << (int)byte4 << endl;

    return 0;
}Code language: PHP (php)

六、注意事项

  • 移位的位数应为非负整数。如果移位的位数大于或等于操作数的位数,结果为未定义行为(C++ 标准未定义)。例如 int 类型通常为 32 位,移位 32 位或更多位的行为不可预测。
  • 左移有符号数的负数或左移导致符号位改变时,可能产生未定义行为。建议对无符号数进行左移。
  • 右移有符号数时,高位补符号位还是补 0 取决于编译器实现,但大多数系统采用算术右移(补符号位)。
  • 移位运算优先级低于算术运算符,混合运算时注意加括号。

七、小结

  • 移位运算符包括左移 << 和右移 >>,均为二元运算符。
  • 左移将二进制位向左移动,低位补 0,高位舍弃,相当于乘以 2 的 n 次方。
  • 右移将二进制位向右移动,低位舍弃,高位补 0(无符号数)或补符号位(有符号数),相当于除以 2 的 n 次方。
  • 移位运算常用于底层编程、性能优化、位掩码操作等场景。
  • 移位位数必须小于操作数的位数,否则行为未定义。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注