The C Programming Language(第 2 版) 笔记 / 6 结构 / 6.9 位字段

目录、参考文献


6.9 位字段

在存储空间很宝贵的情况下,有可能需要将多个对象保存在一个机器字中
一种常用的方法是,使用类似于编译器符号表的单个二进制位标志集合
外部强加的数据格式(如硬件设备接口)也经常需要从字的部分值中读取数据

考虑编译器中符号表操作的有关细节
程序中的每个标识符都有与之相关的特定信息
例如,它是否为关键字,它是否是外部的且(或)是静态的,等等
对这些信息进行编码的最简洁的方法就是使用一个 charint 对象中的位标志集合

通常采用的方法是,定义一个与相关位的位置对应的 “ 屏蔽码 ” 集合:

#define KEYWORD 01 
#define EXTRENAL 02 
#define STATIC 04

enum { KEYWORD = 01, EXTERNAL = 02, STATIC = 04 };

这些数字必须是 2 的幂
这样,访问这些位就变成了用第 2 章中描述的移位运算、屏蔽运算及补码运算进行简单的位操作

语句 flags |= EXTERNAL | STATIC; 在程序中经常出现
该语句将 flags 中的 EXTERNALSTATIC 位置为 1
而语句 flags &= ~(EXTERNAL | STATIC); 则将它们置为 0
并且,当这两位都为 0 时,表达式 if ((flags & (EXTERNAL | STATIC)) == 0) ... 的值为真

尽管这些方法很容易掌握,但是,C 语言仍然提供了另一种可替代的方法
即直接定义和访问一个字中的位字段的能力,而不需要通过按位逻辑运算符
位字段(bit-field),或简称字段,是 “ 字 ” 中相邻位的集合
(word)是单个的存储单元,它同具体的实现有关
例如,上述符号表的多个 #define 语句可用下列 3 个字段的定义来代替:

struct { 
    unsigned int is_keyword : 1; 
    unsigned int is_extern : 1; 
    unsigned int is_static : 1; 
} flags;

这里定义了一个变量 flags,它包含 3 个一位的字段
冒号后的数字表示字段的宽度(用二进制位数表示)
字段被声明为 unsigned int 类型,以保证它们是无符号量

单个字段的引用方式与其它结构成员相同,如 flags.is_keywordflags.is_extern
字段的作用与小整数相似
同其它整数一样,字段可出现在算术表达式中
因此,语句 flags.is_extern = flags.is_static = 1;is_externis_static 位置为 1
语句 flags.is_extern = flags.is_static = 0;is_externis_static 位置为 0
下列语句:

if (flags.is_extern == 0 && flags.is_static == 0) 
    ...

用于对 is_externis_static 位进行测试

字段的所有属性几乎都同具体的实现有关
字段是否能覆盖字边界由具体的实现定义
字段可以不命名,无名字段(只有一个冒号和宽度)起填充作用
特殊宽度 0 可以用来强制在下一个字边界上对齐

某些机器上字段的分配是从字的左端至右端进行的,而某些机器上则相反
这意味着,尽管字段对维护内部定义的数据结构很有用,但在选择外部定义数据的情况下,必须仔细考虑哪端优先的问题
依赖于这些因素的程序是不可移植的
字段也可以仅仅声明为 int,为了方便移植,需要显式声明该 int 类型是 signed 还是 unsigned 类型

字段不是数组,并且没有地址,因此对它们不能使用 & 运算符


目录、参考文献

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值