参考资料:位域(位段)用法,对齐机制_位域操作_~QwQ~的博客-CSDN博客
位域是指:数据在存储时不需要一个完整的字节,只需要占用一个或者几个二进制位,为了更好的使用内存空间,C语言提供了位域这种数据结构
在定义结构体时直接指定某个成员变量占用的二进制位数(BIT)
在 : 后面数字来限定成员变量占用的位数
#include
#include
typedef struct {
uint8_t value_1 : 1;
uint8_t value_2 : 3;
uint8_t value_3 : 4;
}BitUnion;
int main() {
BitUnion data;
data.value_1 = 1;
data.value_2 = 3;
data.value_3 = 10;
printf("data = 0x%x, sizeof_data = %d", data, sizeof(data));
return 0;
}
在上面给定的位域结构中,高位为value_1,但是这里也有大段存储和小段存储的区别;
这里插播一下大小端存储的简单介绍:大小端存储是计算机用于处理多字节数据的不同方式,在内存中存储多字节数据时,字节的存储习惯
大端存储是指(Big-endian)将多字节数据的高位字节存储在低地址,低位字节存储在高地址,就是从左边往右边读
小端存储是指(Little-endian)将多字节数据的低位字节存储在低地址中,高位字节存储在高地址中,就是从右边往左边读。
大端存储和小端储存的选择一般是由计算机体系结构决定的,X86架构使用小端存储,在arm架构使用的是大端存储。
参考文献:存储概念|详解大小端存储_大端存储和小端存储_DADONGOOO的博客-CSDN博客
如上示例所示:value_1、value_2、value_3分别使用1个bit位、3个bit位、4个bit位,共使用了8个bit即一个字节
打印结果位为 :data = 0xa7, sizeof_data = 1
位域的对齐:内存对齐机制
计算机内存是以字节为单位进行划分的,CPU通过地址总线访问内存时,一次能处理多少字节的数据就会让地址总线读几个字节的数据,32位的CPU一次处理4字节的数据,每次就从内存中读取4字节的数据,少了浪费主频,多了没有哟个。64位的处理器每次读取8字节。
对于程序中变量来说,变量最好位于一个寻址步长范围内,这样一次就可以读取到变量的值,如果跨步长存储,就需要读取两次,然后拼接数据,效率低下。
内存对齐与硬件相关,但是决定对齐方式是编译器,可以通过编译器修改。
#include
#include
typedef struct {
uint8_t value_1 : 4;
uint8_t value_2 : 8;
uint8_t value_3 : 4;
}BitUnion;
typedef struct {
uint8_t value_1 : 4;
uint8_t value_2 : 4;
uint8_t value_3 : 8;
}BitUnion1;
int main() {
BitUnion data;
BitUnion1 data1;
memset(&data, 0 ,sizeof(data));
memset(&data1, 0, sizeof(data1));
data.value_1 = 0xf;
data.value_2 = 0xff;
data.value_3 = 0xf;
uint8_t* P_data = (uint8_t*)&data;
for (uint8_t i = 0; i < sizeof(data); i++) {
printf("data[%d] = 0x%x\r\n", i, P_data[i]);
}
data1.value_1 = 0xf;
data1.value_2 = 0xf;
data1.value_3 = 0xff;
uint8_t* P_data1 = (uint8_t*)&data1;
for (uint8_t i = 0; i < sizeof(data1); i++) {
printf("data[%d] = 0x%x\r\n", i, P_data1[i]);
}
return 0;
}
上示例 BitUnion 与预期设计有误的原因是由位域的具体存储规则导致的:
当相邻成员的类型相同时,如果它们的位宽之和小于类型的 sizeof 大小,那么后面的成员紧邻前一个成员存储,直到不能容纳为止;
如果它们的位宽之和大于类型的 sizeof 大小,那么后面的成员将从新的存储单元开始,其偏移量为类型大小的整数倍。
位段:
位段也叫位域,位段会在结构体的基础规定每个成员变量的大小,大小的单位是二进制位。
在有些信息存储时,并不需要占用一整个字节,而只需要一个或几个二进制位的大小空间,例如在存放一个开关量时,只有 0 和 1 两种状态,用 1 位二进位即可。