数据结构 -- 位域
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构 -- 位域相关的知识,希望对你有一定的参考价值。
参考技术A一个字节有8位,在存储时有些数据并不需要占用一个完整的字节,只需要占用一个或几个二进制位即可。例如开关只有通电和断电两种状态,用 0 和 1 表示足以,也就是用一个二进位。基于这种考虑, C 语言提供了『 位域 』这个数据结构。
在结构体定义时,我们可以指定某个成员变量所占用的二进制位数(Bit),这就是位域。来看下面的例子:
当限制了成员的位数时,如果给成员赋值超过其位数,则会导致数据溢出。来看下面的例子:
上面定义了结构体变量a,包含一个非位域成员m,以及两个位域成员n、ch。分别进行两次赋值并输出,输出结果如下所示:
第一次赋值的输出结果分析:
第二次赋值的输出结果分析:
位域的储存规则如下:
位域实质上是含有位域成员的结构体,所以除了遵循这个储存规则外,还需要遵循结构体分内存对齐规则,接下来通过如下示例来分析位域的存储逻辑。
示例1:
输出结果分析:
因此,bs总共需要22位内存,即3字节,而根据结构体对齐规则,bs的内存必须为其最大成员类型长度(int)的整数倍,所以最终输出为4字节。
示例2:
输出结果分析:
因此,bs总共需要86位的内存空间,即11字节,而根据结构体对齐规则,bs的内存必须为其最大成员类型长度(int)的整数倍,所以最终输出为12字节。
示例3:
输出结果分析:
因此,bs需要152位的内存,即19字节,经由结构体内存对齐,需要是4字节的倍数,所以最终输出为20字节。
1. 数据结构 -- 结构体Struct
2. 数据结构 -- 共用体Union
C位域操作
位域的概念
1个字节包含8位,有些变量保存的数据不需要占用这么长的空间(比如bool类型,只有两个状态true和false, 1位就可以搞定,剩下的7位就浪费了),这就催生了“位域”结构,位域将1个字节划分成不同的区域,每个区域都有个位域名,程序员可以代码通过位域名访问其中的数据。
位域的声明
类型 位域名:位域长度;
位域结构体,我理解是一种特殊的结构体,其成员变量都是位域,声明如下
struct 位域结构名 类型说明符 位域名:位域长度; ... 类型说明符 位域名:位域长度; ;
基本原则
现有一个简单的结构体
typedef struct Test1 char a:1; int b:2; test1;
1. 位域变量的长度不能大于其类型的长度(sizeof(类型) * 8)
变量char has_assoc的类型位char 1字节 8位,小于定义的10,所以编译器警告
2. 不能用于位域字段的操作:取地址操作符&,取偏移量操作
位域是若干位空间,是没有地址的
3. 位域可以是无名位域,无名位域只能用作填充或调整位置,不能使用。
typedef struct Test1 char a:1; int b:2; int :1; test1;
4. 位域字段不能声明为类的静态成员
5. 位域结构体的大小必须是其最长基本类型大小的整数倍(sizeof(类型) * 8)
6.如果一个字节所剩空间不够存放另一位域时,应从下一单元起存放该位域。也可以有意使某位域从下一单元开始。例如:
struct bs unsigned a:4 unsigned :0 /*空域*/ unsigned b:4 /*从下一单元开始存放*/ unsigned c:4
这个位域定义中,a占第一字节的4位,后4位填0表示不使用,b从第二字节开始,占用4位,c占用4位。
7.不够一个类型的size时,将按其中最大的那个类型对齐。
struct foo4 char a : 2; char b : 3; int c : 1; ;
foo4中虽然三个位域所占用空间之和为6 bit < 8 bit(1 byte),但是由于char和int的对齐系数是不同的,是不能捆绑在一起,那是不是a、b捆绑在一起按照char对齐,c单独按照int对齐呢?我们 打印一下sizeof(struct foo4)发现结果为8,也就是说编译器把a、b、c一起捆绑起来并以int做对齐了。
8.如果位域字段之间穿插着非位域字段,则不进行压缩;
typedef struct Test1 char a:1; int b:2; test1; //运行结果:4 typedef struct Test1 char a:1; int b:2; long c; test1; //运行结果:16
总结:
1) 如果相邻位域字段的类型相同,且其位宽之和小于类型的sizeof大小,则后面的字段将紧邻前一个字段存储,直到不能容纳为止
2) 如果相邻位域字段的类型相同,但其位宽之和大于类型的sizeof大小,则后面的字段将从新的存储单元开始,其偏移量为其类型大小的整数倍;
3) 如果相邻的位域字段的类型不同,则各编译器的具体实现有差异,VC6采取不压缩方式,GCC采取压缩方式;
4) 如果位域字段之间穿插着非位域字段,则不进行压缩;
5) 整个结构体的总大小为最宽基本类型成员大小的整数倍。
以上是关于数据结构 -- 位域的主要内容,如果未能解决你的问题,请参考以下文章