18.位操作宏.md 4.2 KB

位操作宏

判别规则(核心,唯一要记的)

  • 置位 → 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)
  • 正例3(翻转)#define TOGGLE_BIT(reg, bit) ((reg) ^= (1U << (bit))) → 异或 1 翻转,异或 0 保持
  • 正例4(取值)#define READ_BIT(reg, bit) (((reg) >> (bit)) & 1U) → 右移目标位到最低位再 &1
  • 反例1REG &= (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) 永远为假

口述要点(面试怎么讲)

  • 结论先行:置位用或、清零用与非、翻转用异或、读取用移位与
  • 为什么用 1U1U 是无符号 1。① 防符号位溢出:1<<31 在 int 下移进符号位是未定义行为,1U<<31 合法且明确是最高位 ② 无符号右移是逻辑移位(补 0),行为可预期
  • 为什么封装成宏而不是函数:位操作极其频繁,函数调用有压栈/弹栈/跳转开销;宏编译期展开零开销。也可用 inline 函数
  • 替换一段位(先清后置,通用公式):起始位 s、宽度 w,掩码 = ((1U<<w)-1) << sREG = (REG & ~掩码) | ((newVal & 掩码) << s)。原理:先擦黑板(清零目标位,其他保留),再写新字(新值限宽+搬到目标位)。(newVal & 掩码)限宽(防止高位溢出污染相邻位),<< s移位(从 bit03 整块搬到 bit47,位号从右往左数 0 开始)
  • 宏为什么每个参数加括号:本质是文本替换,不加括号传复杂表达式就变味
  • 易错点:清零忘取反;判断 == 1 而非 == 掩码/!=0;位号从 0 开始从右往左数

关系网络

相邻概念 和本主题的关系 孤立理解会犯的错
define vs typedef 位操作宏就是 define 的应用,文本替换+加括号同一套 宏忘加括号、忘取反
位域 位域(声明式)vs 位操作宏(手动可控) 以为位域能替代宏操作寄存器
寄存器操作 SET_BIT/CLEAR_BIT 直接用在寄存器上 寄存器位操作也忘字节序/volatile
HAL 库 HAL 内部就是位操作宏实现的 以为用库就不用懂位操作

学习日期

2026-08-03


每主题一页,复习时只翻本目录。