前言
上一篇文章,我们学习了结构体的相关知识,今天我们来学习和结构体很像的位段
位段
位:指的是二进制位
位段的声明
位段与结构体的声明有两个不同:
1.位段的成员必须是 int、unsigned int 或signed int 。
成员类型是固定的:char类型也可以,但不要char和int类型混用,类型要保证一致
2.位段的成员名后边有一个冒号和一个数字。
- 位段涉及很多不确定因素,位段是不跨平台的,注重可移植的程序应该避免使用位段
第三点在“位段的不跨平台性”会详细介绍
例子
struct A { int a : 2; int b : 3; };
位段的大小
下面代码的运行结果是什么
struct S { int a : 2; int b : 5; int c : 10; int d : 30; }; int main() { struct S s; printf("%zd\n", sizeof(s)); return 9; }
结果:8byte
解释
位,在开始时.提到了,是二进制位(bit位)
我们假设a的范围是0~4,不会更大也不会更小,那么a就不需要用那么大的空间(32个bit位)去存储,它只需要2个bit位就能存储
所以,成员名冒号后面的数字指的就是:用多少个bit位去存储这个成员(数字不能超过类型的最大bit位数)
按照这么算
2+5+10+30 == 48,但结果不对
下面就来介绍位段的内存分配
位段的内存分配
struct S { int a : 2; int b : 5; int c : 10; int d : 30; };
还是这段代码
我们都知道,int类型是32个bit位
a、b、c共占用了17个bit位,剩下15个bit位,存不下d(30个bit位)
就开辟新的整型空间存储d
所以,总大小就是8个字节
这样就很节省空间了
例题
下面通过这段代码,来讲解一下是如何存储的
struct S { char a : 3; char b : 4; char c : 5; char d : 4; }; int main() { struct S s = { 0 }; s.a = 10; s.b = 12; s.c = 3; s.d = 4; return 0; }
开辟空间
根据上面的规则,开辟出三个字节存储a、b、c、d
(如何存储后面会做说明)
赋值
a是10,二进制表示就是:1010
但a只能存储三个bit位,所以此处存的是010
b是10100,只能存四个bit位,是0100
c是011,c有5个bit位,
不够,那就高位为0
d存储的是0100
所以最终存储的就是:
0010 0010 0000 0011 0000 0100(二进制)
22 03 04 cc cc(十六进制)(后面的没开辟,不用管)
位段不跨平台性
- int 位段被当成有符号数还是无符号数是不确定的。
- 位段中最大位的数目不能确定。
16位机器最大16,32位机器最大32,当写成27个bit位时,在16位机 器会出问题。
- 位段中的成员在内存中从左向右分配,还是从右向左分配标准尚未定义。
- 当一个结构包含两个位段,第二个位段成员比较大,无法容纳于第一个位段剩余的位时,是 舍弃剩余的位还是利用,这是不确定的
位段的应用
我们在网络上传输信息的时候,需要先将信息进行封装,
上图解释了需要封装进哪些信息,如果使用位段就能很好的存储进每个数据,如果不用位段,那数据包大小就会很大(现阶段,了解即可)
结语
位段的介绍和学习到这里就结束了
下篇文章我们会学习自定义类型中的枚举和共用体
我们下篇文章见~