一、移位运算符的概念
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 次方。
- 移位运算常用于底层编程、性能优化、位掩码操作等场景。
- 移位位数必须小于操作数的位数,否则行为未定义。