位段
什么是位段
在C语言中有些数据在存储时并不需要占用一个完整的字节,只需要占用一个或几个二进制位即可,基于这种特殊的存储,C语言又提供了一种叫做位域的数据结构。 在结构体定义时,我们可以指定某个成员变量所占用的二进制位数(Bit),这就是位域
位段的声明
位段的声明和结构类似但是有两个不同 e.g. 1.位段的成员必须是 int、unsigned int 或signed int 。 2.位段的成员名后边有一个冒号和一个数字
struct bw{
unsigned m;
unsigned n: 4;
unsigned char ch: 6;
}
struct A
{
int _a : 2;
int _b : 5;
int _c : 10;
int _d : 30;
};
关于位段的内存分配问题
学会了如何声明之后相信有很多小伙伴是不是在思考,这个东东到底在内存中占多少空间呢??这里我们不妨来讨论一下:
printf("%d\n", sizeof(struct A));
通过我们的编译器(vs2019)能得到如下得结果 到这里相信很多小伙伴就以及开始犯糊涂了,这个结构体按照内存对齐原则根据偏移量来计算的话(4+4+4+4)应该为16,为什么结果却为8呢?下面我们来了解一下位段的存储规则 位域的具体存储规则如下:
- 当相邻成员的类型相同时,如果它们的位宽之和小于类型的 sizeof 大小,那么后面的成员紧邻前一个成员存储,直到不能容纳为止;如果它们的位宽之和大于类型的 sizeof 大小,那么后面的成员将从新的存储单元开始,其偏移量为类型大小的整数倍。
通俗版:将上述规则简单通俗的说出来其实就是,在vs2019中位段冒号后面的数字决定这个变量类型所开辟出来的空间,变量将要占有的比特位,例如上面的 bw,n 的类型是 unsigned int,长度为 4 个字节,共计 32 位,那么 n 后面的数字就不能超过 32;ch 的类型是 unsigned char,长度为 1 个字节,共计 8 位,那么 ch 后面的数字就不能超过 8(图中所占空间为6bit)。
到这里就不难解释为什么是8而不是16了: struct A中有4个int 类型的变量,第一个int开辟出4个字节也就是32个bit,但是_a只占2个bit位,故_b占的5个bit也能够放入,_c所占10个bit也能够放入,到_c这一共放了17个bit,还剩下15个bit位,但是_d为30bit,显然放不进,故int _d向内存第二次申请4个字节的空间将30个bit全部放入,故最后的答案为8个字节!
结构体
——结构体,它就将不同类型的数据存放在一起,作为一个整体进行处理。
结构体的基础知识介绍
例如对于学生信息登记表,姓名为字符串,学号为整数,年龄为整数,所在的学习小组为字符,成绩为小数,因为数据类型不同,显然不能用一个数组来存放。 在C语言中,可以使用结构体(Struct)来存放一组不同类型的数据。结构体是一种集合,它里面包含了多个变量或数组,它们的类型可以相同,也可以不同,每个这样的变量或数组都称为结构体的成员(Member)例如:
struct Stu
{
char name[20];
int age;
char sex[5];
char id[20];
};
接下来给大家介绍一下如何定义变量
#include <stdio.h>
int main() {
struct {
char* name;
int num;
int age;
} stu1;
stu1.name = "zhoumin";
stu1.num = 1;
stu1.age = 18;
return 0;
}
枚举
在这里给大家介绍一下一个比较好玩的东西(枚举)enum
枚举类型的定义
他的主要系统结构和结构体非常类似,枚举数据表的值都是整数。第一个枚举成员的默认值为整型的0,后续枚举成员的值在前一个成员上加1。也可以人为设定枚举成员的值,从而自定义某个范围内的整数。
enum Day
{
Mon,
Tues,
Wed,
Thur,
Fri,
Sat,
Sun
};
以上定义的 enum Day就是一个是枚举类型,{}中的内容是枚举类型的可能取值,也叫 枚举常量
枚举的优点
这时候就有小伙伴要说了,我们可以使用 #define 定义常量,为什么非要使用枚举? 给大家介绍一下枚举的优点:
- 增加代码的可读性和可维护性
- 和#define定义的标识符比较枚举有类型检查,更加严谨。
- 防止了命名污染(封装)
- 便于调试
- 使用方便,一次可以定义多个常量
枚举的使用
使用枚举可以一次定义多个变量,如果使用#define的方式要从Mon开始一个一个去定义七遍,显得是不是有点太浪费时间了?下面运用了枚举来处理这事情瞬间就变得非常简单了,一次性全部定义了,是不是很香呢?
#include<stdio.h>
enum week {Mon=1,Tue,Wed,Thu,Fri,Sat,Sun};
int main()
{
printf("%d",Mon);
return 0;
}
联合
联合类型的定义
联合也是一种特殊的自定义类型 结构体和共用体的区别在于:结构体的各个成员会占用不同的内存,互相之间没有影响;而共用体的所有成员占用同一段内存,修改一个成员会影响其余所有成员。 共用体也是一种自定义类型,可以通过它来创建变量,例如:
union data{
int n;
char ch;
double f;
};
union data a, b, c;
联合的特点
联合的成员是共用同一块内存空间的,修改一个成员会影响其余所有成员,这样一个联合变量的大小,至少是最大成员的大小(因为联合至少得有能力保存最大的那个成员)。
# include<stdio.h>
int main() {
union Un
{
int i;
char c;
};
union Un un;
printf("%d\n", &(un.i));
printf("%d\n", &(un.c));
un.i = 0x11223344;
un.c = 0x55;
printf("%x\n", un.i);
return 0;
}
联合大小的计算
1.联合体union特性 联合体所有成员变量共享内存,相对于联合体首地址偏移量都为0 同一时间只能存储1个被选择的变量,对其他成员变量赋值会覆盖原变量 2.联合体大小计算准则 联合体大小要至少能容纳最大的成员变量 联合体大小要是所有成员变量类型大小的整数倍
#include<stdio.h>
int main() {
union Un1
{
char c[5];
int i;
};
union Un2
{
short c[7];
int i;
};
printf("%d\n", sizeof(union Un1));
printf("%d\n", sizeof(union Un2));
return 0;
}
在清楚了上述的规则之后,我们来尝试运用一下,在union un1中我们可知至少要有51的空间,空间又必须为4的倍数,故sizeof(union un1)=8;再来看看union un2 中我们知道至少要有27的空间,空间又必须为4的倍数,故sizeof(union un2)=16;
|