## 位操作宏 ## 判别规则(核心,唯一要记的) - **置位 → `reg |= (1U << bit)`;清零 → `reg &= ~(1U << bit)`(掩码必须取反);翻转 → `reg ^= (1U << bit)`;取值 → `(reg >> bit) & 1U`** - 掩码统一是 `1U << bit`,区别只在运算符和取反 一句话:**"或放 1、与非放 0、异或翻转、移位读位。"** ## 抽象描述(一句话本质) 位操作就四种"掩码 + 运算符"组合:置位 = 或,清零 = 与非,翻转 = 异或,取值 = 右移+与。掩码统一 `(1U << bit)`。宏封装 = 编译期展开无调用开销,位的位置完全由你控制。 ## 正反例(建立直觉) - **正例1(置位)**:`#define SET_BIT(reg, bit) ((reg) |= (1U << (bit)))` → 或 1 置位,或 0 保留 - **正例2(清零)**:`#define CLEAR_BIT(reg, bit) ((reg) &= ~(1U << (bit)))` → 与 0 清 0,与 1 保留。⚠️ 必须取反 `~(1<> (bit)) & 1U)` → 右移目标位到最低位再 &1 - **反例1**:`REG &= (1 << 3);` 想清零第 3 位 → 错!把第 3 位以外全清 0 - **反例2**:宏参数不加括号 → 文本替换变味(`SET_BIT(A|B,2)` 展开成 `A|B |= ...` 语法错) ## 易混对比(四句口诀) | 操作 | 运算符 | 掩码形式 | 口诀 | | ---- | ---------- | ---------------- | ----------- | | 置位 | `\|` | `1 << bit` | 或 1 置位 | | 清零 | `&` | `~(1 << bit)` | 与 0 清零 | | 翻转 | `^` | `1 << bit` | 异或 1 翻转 | | 取值 | `>>` + `&` | `(x >> bit) & 1` | 右移再与 1 | ## 变体验证(3 题,全过=学会) 1. 陷阱题:`REG &= (1 << 3);` 清零第 3 位 → **不对**,需取反 `~(1<<3)`,否则把第 3 位以外全清零 2. 构造:一次置位第 2、7 位 → **`REG |= (1U<<2) | (1U<<7);`** 3. 构造:判断第 4 位 → `if (REG & (1<<4))` 和 `if ((REG>>4)&1)` 作为**布尔条件等价**;作为**值不等价**(前者得 0x10 不是 1)。经典坑 `if ((REG & (1<<4)) == 1)` 永远为假 ## 口述要点(面试怎么讲) - **结论先行**:置位用或、清零用与非、翻转用异或、读取用移位与 - **为什么用 1U**:`1U` 是无符号 1。① 防符号位溢出:`1<<31` 在 int 下移进符号位是未定义行为,`1U<<31` 合法且明确是最高位 ② 无符号右移是逻辑移位(补 0),行为可预期 - **为什么封装成宏而不是函数**:位操作极其频繁,函数调用有压栈/弹栈/跳转开销;宏编译期展开零开销。也可用 `inline` 函数 - **替换一段位(先清后置,通用公式)**:起始位 s、宽度 w,掩码 = `((1U<