前言
最近在尝试阅读一些系统库的源码,但是其中存在很多让我感到既熟悉又陌生的语法。经过资料查阅,发现是 C 语言中的共用体和位域。于是,趁着课本还没有扔掉,将一些相关的知识点记录在本文。
文章目录
- 前言
- 共用体 (union)
- 枚举 (enum)
- 位域
- 参考资料
共用体 (union)
公用体和结构体相似,也是一种数据构造机制。但是结构体中的各成员变量顺序排列存储,每个成员变量都有自己独立存储空间,而共用体中所有成员变量共享同一片内存区域,一个共用体变量在每个时刻里只能保存它的某个成员变量的值。
定义格式如下:
union 共用体名 {
成员列表
};
下面是共用体和结构体占用内存的情况:
#include <stdio.h>
union UnionData {
int a;
float b;
double c;
char d;
};
struct StructData {
int a;
float b;
double c;
char d;
};
int main() {
printf("%lu %lu\n", sizeof(UnionData), sizeof(StructData));
return 0;
}
控制台输出结果:
8 24
共用体能支持在同一块内存区域对不同的数据类型进交替使用,增加了灵活性,节省了内存,通常在系统库中会有所应用。
枚举 (enum)
枚举 (enumeration) 是一系列命名的整型常量,它是一种基本数据类型,而不是一种构造类型。在“枚举”类型的定义中,我们需要列举出所有可能值,就像列举一周七天、一年四季等。
定义格式如下:
enum 枚举名 {枚举列表};
枚举的使用例子如下:
#include <stdio.h>
// 枚举定义
enum Season {
SeasonSpring = 1,
SeasonSummer,
SeasonAutumn,
SeasonWinter
};
int main () {
Season a = SeasonSpring;
switch (a) {
case SeasonSpring:
printf("SeasonSpring\n");
break;
case SeasonSummer:
printf("SeasonSummer\n");
break;
case SeasonAutumn:
printf("SeasonAutumn\n");
break;
case SeasonWinter:
printf("SeasonWinter\n");
break;
}
return 0;
}
控制台输出结果:
1 2 3
位域
有些数据在存储时并不需要占用一个完整的字节,只需要占用一个或几个二进制位即可。例如开关只有通电和断电两种状态,用 0 和 1 表示足以,也就是用一个二进位。
出于节省内存的角度考虑,就有了位域这种设计。位域是 C 语音中一种特殊的结构体成员,它允许我们指定它所占的内存位数。
定义格式如下:
struct 位域结构名 {
类型说明符 位域名 : 位域长度;
};
说明:
- 一个位域必须存储在同 1 个字节中,不能跨两个字节。如果一个字节所剩的空间不足以存储下一个位域时,应该从下一个字节开始存储。
- 位域长度不能大于 1 个字节长度,也就是说不能超过 8 位。
- 位域的数据类型只能是 int、unsigned int、char、枚举等类型。
- 位域可以没有位域名,因为无名的位域是不能使用的,所以只是用作填充或调整位置的作用。例如:
struct BitStruct { int a : 4; int : 2; // 空域,不能使用 int b : 4; int c : 4; }
参考资料
- https://www.runoob.com/cprogramming/c-bit-fields.html
- https://book.douban.com/subject/26792521/
本文主要对 C 语言中,共用体、枚举和位域等三块内容做简单介绍,涉及到他们在工程中应用的方面很少,如果后面阅读系统源码的过程遇到了,会再做进一步补充。