16.位域.md 4.2 KB

位域

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

  • 位域大小 = 按分配单元分块(int 型 = 4 字节一块,char 型 = 1 字节一块),同一块内多个位域共享
  • 三大坑:可移植性差(布局由编译器定)、不能取地址、赋值超位数自动截断
  • 嵌入式寄存器/协议帧:宁可选手动位操作宏,位的位置必须自己说了算

一句话:"位域是声明式省内存,但布局不归你管——省了空间,丢了控制。"

抽象描述(一句话本质)

位域 = 在结构体里给成员指定"用几个 bit",把多个小标志压缩进一个字节/字里省内存。声明式好写好看,但内存布局(分配单元、大端小端位序)由编译器决定,可移植性差。

正反例(建立直觉)

  • 正例1struct Flags { unsigned int a:1; b:3; c:4; }; → 共 8 bit 挤进第一个 int 分配单元 → 占 4 字节(不是 1!)
  • 正例2(省内存)struct Status { unsigned char ready:1; busy:1; error:1; spare:5; }; → 1 字节装 8 个标志;对比 8 个独立 char 要 8 字节 → 省 7 字节
  • 正例3(用)s.ready = 1; if (s.busy) {...}
  • 反例1(可移植性):位域布局(分配单元、位序)由编译器决定,跨平台/跨编译器可能完全不同
  • 反例2(不能取地址)&s.ready 非法——没有独立字节就没有地址
  • 反例3(截断)unsigned int x:2; 最多存 0~3,s.x = 5;(101b)截断成 1

易混对比

位域 位操作宏
形式 声明式,好写好读 手动掩码 SET_BIT/CLEAR_BIT
可移植 (布局由编译器定) 好(自己控制位)
嵌入式寄存器 少用(布局不保证和寄存器定义一致) 常用(可控、明确)

变体验证(3 题,全过=学会)

  1. struct { unsigned char a:1; ... h:1; };(8 个 1 位)→ sizeof = 1 字节(char 型位域,8 bit 装 1 字节)
  2. struct { unsigned char a:4; b:4; c:4; }; → sizeof = 2 字节(第一个 char 装 a+b,第二个装 c)
  3. 陷阱题:struct { unsigned int x:2; } s; s.x = 7;s.x = 3(7 = 111b,2 位域截断取后两位 11b = 3)

口述要点(面试怎么讲)

  • 结论先行:位域按分配单元分块(int 4 字节 / char 1 字节),同一块内共享
  • 省内存的代价:可移植性(布局、位序全由编译器定)+ 不能取地址 + 赋值截断
  • 为什么嵌入式寄存器不用位域:位操作宏虽不省代码,但位的位置、顺序完全由你控制,和硬件手册一一对应
  • 和 pack(1) 的关系:位域管字节内位布局,pack(1) 管字节级紧凑——协议帧里用位域往往必须配合 pack(1) 去填充。但位域布局 + 位序和编译器/大小端强相关,跨平台一编就错位 → 协议帧不推荐位域,更常用位操作宏/手动掩码
  • 位域和普通成员混用不会编译错误;普通成员按对齐排、位域挤在分配单元内,混用让布局更难预测。惯例:位域集中放一组,别混
  • 易错点:int 型位域占 4 字节不是 1;赋值超位数截断不报错;位域不能取地址

关系网络

相邻概念 和本主题的关系 孤立理解会犯的错
结构体对齐 同一套布局规则:位域按分配单元分块 以为位域不用管对齐
位操作宏 位域(声明式、不可移植)vs 宏(手动、可控) 以为位域能替代寄存器位操作
struct vs union 都是内存压缩手段 以为两者互斥
通信协议 位域 + pack(1) 配合,但跨平台错位风险 以为位域天然适合协议帧

学习日期

2026-08-03


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