原始题目

以下代码的输出是什么?

#include <iostream>
using namespace std;
int main() {
    int a = 3;
    cout << (a << 2 | 1) << endl;
    return 0;
}

答案:13


三步算出结果

  1. a = 3,二进制是 11
  2. 先算 a << 211 左移 2 位 → 1100 = 12
  3. 再算 | 1:最低位置 1 → 1101 = 13
a        = 0000 0011   (3)
a << 2   = 0000 1100   (12)   ← 左移 2 位 = ×4
| 1      = 0000 1101   (13)   ← 最低位置 1

真正的考点:<<| 谁先算

很多人以为位运算都是“从左到右”算,其实优先级不一样

\[ \texttt{<<} \ \texttt{>>} \ > \ \texttt{\&} \ > \ \texttt{\textasciicircum} \ > \ \texttt{|} \]

移位运算 << 的优先级高于按位或 |,所以:

a << 2 | 1      ==  (a << 2) | 1   = 13   ✅

如果误以为 | 先算,就会得到:

a << (2 | 1)    = 3 << 3 = 24              ❌

记忆口诀:位运算家族里,移位最“紧”,& 次之,^ 再次,| 最松。 所以混写时一定加括号,既别人看得懂,也不怕记错优先级。

常见写法对比(a = 3)

表达式 等价写法 结果 二进制
a << 2 (a << 2) 12 1100
a << 2 \| 1 (a << 2) \| 1 13 1101
a << (2 \| 1) a << 3 24 11000
(a \| 1) << 2 12 1100
a << 2 + 1 a << 3 24 11000

最后一行也很坑:算术 + 的优先级同样高于移位 <<,所以 a << 2 + 1a << (2+1),不是 (a<<2)+1

这段代码的语义

a << 2 | 1 实际在做两件事:

  • a << 2:把 a 乘 4
  • | 1:把结果最低位置 1

合起来就是:a × 4 后再把最低位强制变成 1(如果末位已经是 1,值保持不变)。

// 等价写法(对非负 a)
int r = (a * 4) | 1;

实用小技巧

x | 1      // 把 x 变成不小于 x 的最小奇数(末位置 1)
x & ~1     // 把 x 末位清零(变成偶数)
x << k     // x × 2ᵏ(注意溢出)
x >> k     // floor(x / 2ᵏ)

考点总结(CSP-J 初赛选择题)

  1. 移位 << >> 优先级 高于 & ^ |,但 低于 算术 + -
  2. a << k = \(a \times 2^k\)a >> k = \(\lfloor a / 2^k \rfloor\)
  3. x | 1 置最低位为 1;x & (x-1) 清最低位的 1。
  4. 秒杀技巧:遇到混合位运算,先按优先级补上括号再动手算,不要凭直觉从左到右。

思考题

int a = 3; 时,cout << (a << 2 + 1); 输出多少?

答案 输出 24。因为 + 的优先级高于 <<,等价于 a << (2+1) = 3 << 3 = 24,而不是 (3<<2)+1 = 13