左移<<安全用于无符号数,有符号数溢出为未定义行为;右移>>对无符号数逻辑右移、有符号数算术右移;IO中的<<和>>是重载操作符,与位运算无关;移位优先级高于比较但低于加减。

左移 << 是乘 2 的幂,但只对无符号数安全
左移 << 本质是把二进制位整体向左移动,空出的低位补 0。对非负整数来说,a << n 等价于 a * (1 << n),也就是乘以 2^n。
但要注意:int 是有符号类型,C++ 标准规定:对有符号数左移导致溢出(比如 INT_MAX << 1)是未定义行为(UB)。编译器可能生成任意结果,甚至优化掉整个分支。
- 安全做法:左移前确保操作数是无符号类型,例如用
unsigned int或显式转换(unsigned int)a << n - 移位位数不能超过类型总位数(如
int通常是 32 位,a << 32在 C++20 前是 UB;C++20 起要求为 0) - 移位数为负值(如
a << -1)直接触发未定义行为,编译器通常报错或静默忽略
右移 >> 分逻辑右移和算术右移,取决于类型
右移 >> 向右移动位,高位补什么,由操作数类型决定:
- 对
unsigned类型,高位补 0(逻辑右移),等价于无符号除法:a >> n≈a / (1U << n) - 对
signed类型(如int),C++ 标准允许实现选择补符号位(算术右移)或补 0(逻辑右移),但所有主流编译器(GCC、Clang、MSVC)都采用算术右移 —— 即高位补原符号位,保持负数仍为负数 - 因此
-8 >> 1通常是-4,而不是2147483644(补 0 的结果)
注意:右移位数同样不能为负,也不能 ≥ 类型宽度;否则行为未定义。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
立即学习“C++免费学习笔记(深入)”;
用 << 和 >> 做 I/O 时完全不是位运算
这是初学者最常混淆的点:std::cout << x 中的 << 是重载的流插入操作符,和位左移毫无关系;同理 std::cin >> x 的 >> 是提取操作符。
- 它们只是“借用了”位运算符的符号,语义完全不同
- 编译器靠参数类型区分:
int << int触发位运算,std::ostream & << int触发流操作 - 别试图用
std::cout << (a << 2)来“调试位移”,括号外的<<仍是流操作 —— 这没问题;但若写成std::cout << a << 2,就变成输出a再输出2,不是位移
移位和乘除混用时,编译器不一定优化,且语义不同
虽然 a << 1 在数学上等于 a * 2,但两者语义不同:移位是位级操作,乘法是算术操作。现代编译器(如 GCC -O2)通常能将简单乘 2 的幂优化为移位,但反过来不成立 —— 移位无法替代乘法的全部能力。
-
a * 3无法用单次移位表达,而a << 1永远只能是乘 2 的幂 - 对负数,
-5 * 2 == -10是确定的,但-5 << 1是未定义行为 —— 别为了“看起来快”强行替换 - 在嵌入式或性能关键路径中,若需明确位操作(如寄存器配置、掩码生成),必须用移位;若只是做数值计算,优先用
*和/,更清晰、更安全
真正容易被忽略的是:移位操作符的优先级低于加减,但高于比较。写 a << 2 + 1 实际是 a << (2 + 1),而 a + 1 << 2 是 a + (1 << 2) —— 不加括号极易出错。

















