用一位表示一种状态
位标志的思路是把多种互不排斥的开关压进一个整数:每个开关占一个比特,值为 2 的幂次掩码。判断是否存在用按位与,置位用按位或并赋值,清位用按位与取反,取反用按位异或。这样一份配置或一个协议字段就能同时表达多项状态,读写都只需常数次操作。
基本信息
| 掩码取值 | 1、2、4、8、16 等 2 的幂,或写成 0x01、0x02、0x04 |
|---|---|
| 判位 | (flags & MASK) != 0,注意加括号 |
| 置位 | flags = flags | MASK,可简写为 flags |= MASK |
| 清位 | flags = flags & ~MASK,取反后与 |
| 多位字段 | 先用右移对齐再与掩码:((flags >> shift) & field_mask) |
典型使用场景
- 一个整数承载多项开关,减少配置项与协议字段数量
- 解析协议头里的标志位,如 TCP 标志与链路状态位
- 处理文件权限与特殊位,八进制写法本身就是位组合
- 解析事件与告警等级:一个值同时表示多个已触发条件
- 批量查询筛选:用位运算在内存里做集合判断
读写与拆字段
读写与拆字段
READ, WRITE, EXEC = 0x1, 0x2, 0x4 # 三个独立标志位
flags = 0
flags |= READ | WRITE # 置位:0b011
flags &= ~WRITE # 清位:0b001
bool(flags & EXEC) # 判位:False
# 多位字段:低 4 位存版本号,高 4 位存通道
raw = (3 << 4) | 5 # 通道 3,版本 5
channel = (raw >> 4) & 0x0F
version = raw & 0x0F
# 标记已处理过某状态
seen ^= READ # 异或等于切换该位常见位组合速查
| 场景 | 位值 | 说明 |
|---|---|---|
| 八进制权限 4 2 1 | 读 4、写 2、执行 1 | 三位一组,即一组 rwx |
| 特殊权限位 | 4 2 1 位于权限位之前 | 分别对应设置用户、组 ID 与粘滞位 |
| TCP 标志位 | 低六位分别对应 FIN、SYN、RST、PSH、ACK、URG | 抓包中常以十六进制显示,按位读更方便 |
| 事件等级 | 2 的幂次逐级递增 | 用按位或合并多等级时注意最大值上限 |
| 掩码全一 | 0xFF、0xFFFF 表示全选或保留位 | 与全一掩码相与等于取值 |
JavaScript 的位运算作用于 32 位有符号整数:第 31 位会被当作符号位,需要无符号结果时用 >>> 0 归一,超过 32 位的标志位应改用 BigInt 或数组表示。
位运算极易被优先级坑到:比较运算符优先级高于按位与,写 f & MASK == 0 会被解析成 f & (MASK == 0),判位永远得到错误结果。所有按位运算都加括号。