2.位段
2.1位段的基本知识
知识点:
位段是一种附于结构体之上的一种改变结构体成员所占内存的功能(类似结构体的一种新的结构体),位(比特位);
位段的用法是在结构体成员后加上冒号和数字;位段的成员一般只是int / unsigned int / signed int 、char(整形家族);
位段的意义对于数值来说有时候一些数值并不一定需要一个整形的大小(32bit)才能放的下,他可能只需几个bit即可放的下,所以通过位段的形式来对所开辟的空间进行限制来节约空间
细节:
一般来说位段里的成员类型都是相同的或者是其有无符号位的类型
通过其结构体成员的类型来依次开辟空间4byte(int)、1byte(char),只有当不够的时候才会再次开辟
位段的使用,对于后面的数字来说不能超过其自身类型大小int (32bit)char(8bit)
因为位段涉及这许多的不确定因素,所以位段是不跨平台的,如果是可移植程序中要慎用(避免)
通过代码进行具体讲解:
#define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h> struct A { int a : 2; int b : 5; int c : 10; int d : 30; }; int main() { printf("%d", sizeof(struct A));//最终打印出8,而不是16 return 0; }
对于上面的代码为什么最终大小是8:
首先其全部是int类型,所以先开辟32bit,a的所需大小是2bit,所以还剩30,b:5,所以还剩25、c:10 ,还剩15,当到d时,所剩的空间已不够,所以就需要才开辟32bit,所以最终开辟64bit(8byte)
对于第一次开辟的空间最后还剩下的15bit 是否使用 这C语言中并没有严格的规定 所以就导致位段有不确定因素
对于位段的跨平台问题
1. int 位段被当成有符号数还是无符号数是不确定的。
2. 位段中最大位的数目不能确定。(16位机器最大16,32位机器最大32,写成27,在16位机器会出问题,此时整形的最大bit是16)。
3. 位段中的成员在内存中从左向右分配,还是从右向左分配标准尚未定义(vs2019右到左)
4. 当一个结构包含两个位段,第二个位段成员比较大,无法容纳于第一个位段剩余的位时,是舍弃剩余的位还是利用,这是不确定的(vs舍弃)。
练习:
当开辟了一个32bit的空间第一个 成员变量的值 从左边开始放还是从右边开始放也就是对于位段在内存中是如何存成员的数据的?
以及当空间不够时,到底是利用剩余的空间再加上新开辟的空间还是直接只用新开辟的空间? 下面通过调试的方法来看
通过调试的方法我们可以得到在vs2019环境下:
(小端存储):实际应该是 04 03 62 此时位段是将前名的成员从右往左开始放的,并对于前面剩下的空间也不会利用(最后的03 04 就能看出:04(d)并没有用到前面剩下的空间0)
数据的存储问题
对于开辟好的空间存放成员的数据时他会从右往左一次放进对应的bit
如果之前开辟的空间不够后他不会再利用那些不够的空间,而是直接将数据放在新空间内
对于b.d 我就不写了方法是一样的,先将要存的数字转化成二进制,在通过所分配的bit 将这个二进制放到内存中,如果空间不够就开辟新空间(新空间开辟的地址大于老空间)
最终大小就是3byte
3.枚举(enum)
对也就是一一列举,对一些值进行列举:如一周的星期,一年的月份
将这些周进行列举,创建一个枚举常量来确定这个实际的事
3.1枚举的定义
知识点:
语法如下
enum name
{
e1,
e2,e3
};
对于枚举名(name)一般起的有意义点,枚举常量(e1,e2,e3)间用逗号隔开最后一个不需要加,而枚举常量是枚举变量的可能取值(enum name s = e1)
//如星期 enum Day { Mon, Tues, Wed, Thur, Fri, Sat, Sun };
细节:
每个枚举常量都有对应可代替的数值,当你不初始化时他默认从0开始递增
这样你就可以通过Mod来代替0;
当然你还有自定义开始的值,从后开始跟着递增,如:
所以你在整月份时就可以将 Jan = 1 然后以此递增
不能在枚举外的其余地方进行枚举常量的修改
对于枚举定义常量相较于#define定义常量的区别:
增加了可读性
有了类型检查
将常量进行了封装让其不能被轻易更改
可以调试
方便使用,一次定义多个常量
对于枚举的大小,因为其内容可以代表整形所以其大小也和整型一样(4byte)
4.联合体(共用体union)
知识点:
联合体同样也是一种自定义类型,这种类型定义的变量也包含一系列的成员,而这些成员不同于结构体他们是共用同一块空间的(他就想一个自习室,大家都可以用,不过大家的用法不同,你可能要用到电脑、而别人只看书空间共享,当使用方法可能不同,并且假如上一个人在使用完后没有拿自己的电脑,就会导致下一个人来对时候电脑还在这个空间内)。
联合体的大小
联合体这块空间的大小是至少等于一系列成员中最大的成员的类型大小
并且这块空间的大小也要对齐其中最大对齐数的整数倍
细节:
#define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h> union A { char arr[6]; int a; }; int main() { printf("%d", sizeof(union A));//8 return 0; }
附:对于联合体所共用的空间,当前一个成员用过后,如果另一个成员使用时并不覆盖的话仍然会存留之前的数据,并不会自动销毁
练习:
写一个函数来实现判断计算机是大端还是小端
union A { char arr; int i; }; int Judge_system(union A* a) { a->i = 1; return a->arr; } int main() { union A a = {0}; int ret = Judge_system(&a); if (ret == 0) { printf("大端\n"); } else { printf("%d小端\n",ret); } return 0; }
本章完。预知后事如何,暂听下回分说。