位段:与结构体的定义相似,但是也有不同之处
1.位段中的成员变量必须是整型:int、signed int、unsigned int、char
2.位段中的所有成员变量的数据类型相同
3.位段成员名后面有一个冒号和数字
位段,指的是二进制位;由于位段中的数据成员需要表示的状态是有限的,所以需要少数的比特位就可以表示出所有的状态
struct S
{
int a : 5;
int b : 10;
int c : 2;
};
// 对于位段S来说,a仅仅需要5个bit,b仅仅需要10个bit,c仅仅需要2个bit
// 对于整个S来说,仅仅需要17个比特位
位段中的内存分配:
位段开辟内存时,空间按照需要以四个字节(int)或一个字节(char)的方式进行开辟的
当开辟的四个字节存放一定成员,剩余的空间不够存放下一个成员时,系统会舍去剩余的空间,另外在开辟四个字节进行存放
注意:1.对于位段来说,如果成员是int,则每一个成员所占用的二进制位不能超过32,即后面跟的 数字不能超过32;如果是char,则不能超过8
2.给位段中的成员赋的值,如果这个值的二进制位超过规定存储的二进制位数,则舍去部分,按照规定的二进制位存储
位段相对于结构体来说,大大地节省了空间,但是位段有很多不确定性:
int位段中的最高位被当成有符号数还是无符号数,是不确定的
位段中需要的比特位的最大值是不确定的,对于16位机器,最大是16;对于32位机器。最大是32
位段中的成员在内存中是从左向右进行分配还是从右向左进行分配是不确定的
一个结构包含两个位段时,第一个位段无法容纳下一个成员时,应该舍弃剩余的空间还是利用,不确定
所以位段相对于结构体,可以达到相同的效果,可以很好地节省空间,但是有跨平台性问题
位段的主要应用:网络上的数据压缩传输
枚举:enum,将所有可能的取值一一列举出来
enum tag
{
枚举的所有可能取值
};
定义枚举变量时,只能定义为所有的枚举可能取值,不能定义为其他的
在一个枚举定义中,所有的枚举中的可能取值都是常量,默认从0开始,也可直接改变
enum Color
{
red, // 0, 默认从0开始
green, // 1
blue // 2
};
enum Color c = red;
// 定义时不能直接使用数字
// enum Color c = 0; -- error,类型不同,无法完成类型转换
printf("%d %d %d\n", red, green, blue); // 0 1 2
enum Sex
{
Male = 1, // 赋初值为1
Female // 2
};
enum Week
{
Monday = 2, // 2
Tuesday, // 3
Wednesday, // 4
Thursday, // 5
Firday, // 6
Saturday, // 7
Sunday = 15 // 15
};
相对于define定义的常量:使用枚举常量的优点:1.增强了代码的可读性和可维护性;2.枚举定义有类型检查,更加严谨; 3.防止命名冲突; 4.便于调试; 5.使用方便,一次定义多个常量
占用内存:
枚举常量--所有可能性取值,相当于一个数字,占用的内存就是一个整型的大小--4字节
联合体:union,共用体,所有的成员共用同一块内存空间
union U
{
char c;
int a;
};
// 创建联合体变量
union U u;
printf("%d\n", sizeof(u)); // 4
printf("%s\n", &u); // 00000004120FF7A4
printf("%s\n", &(u.c)); // 00000004120FF7A4
printf("%s\n", &(u.a)); // 00000004120FF7A4
联合体占用的内存:
联合体中的所有成员共用同一块内存空间,所以一个联合体变量的大小,至少是最大成员的大小,确保联合体至少有能力保存最大成员
当最大成员不是联合体最大对齐数的整数倍时,就要对齐到最大对齐数的整数倍
由于联合体中所有的成员共用同一内存空间,所以一个成员发生变化时,其他成员也会变化
联合体的应用:判断内存的大小端存储
int check_sys()
{
union Un
{
char c;
int i;
};
Un.i = 1; // 00 00 00 01
/*if (Un.c == 0) // 01 00 00 00 -- 小端
return 0;
else // 00 00 00 01 -- 大端
return 1;*/
return Un.c;
}