C/C++节约存储数据空间的方法:位域

     有些时候,根据一个数据的取值范围(主要看最大取值),其在存储时并不需要占用一个完整的字节,只需要占用一个或几个二进制位即可。例如开关只有通电和断电两种状态,用0和1表示足以,也就是用一个二进位。为了节省存储空间,并使处理简便,C/C++语言又提供了一种数据结构,叫做“位域”或“位段”。位域的定义和位域变量的说明位域定义与结构定义相仿。

      struct 位域结构名  { 位域列表 }; 

     其中位域列表的形式为: 类型说明符 位域名:位域长度。 

      比如,我们想用一个struct来表示年-月-日,由于我们知道月份的取值范围是1-12,用4bit就可以表示;日的取值范围是1-31,用5bit就可以表示。这样我们就可以这样来定义struct Data_1,只需要占用4byte就可以存储。

struct Data_1  // sizeof(Data_1) = 4 
{
unsigned int year  :23;  
unsigned int month :4; //range: 1-12
unsigned int day   :5; //range: 1-31  
};

再比如,有8个开关量,可以用位域来表示。

struct TEST_1    // sizeof(TEST_1) = 1
{
    bool a:1;
    bool b:1;
    bool c:1;
    bool d:1;
    bool e:1;
    bool f:1;
    bool g:1;
    bool h:1;
};

    关于位域的使用,有以下几个规则:

  1. 位域可以无位域名,这时它只用来作填充或调整位置。无名的位域是不能使用的。
  2. 位域的长度不能大于数据类型本身的长度,比如int类型就不能超过32位。
  3. 不能对位域进行 取地址操作
  4. 可以直接对位域进行赋值,但要注意赋的值不要超过位域的最大值范围,否则会出现溢出,如果cout,得到的是截断后的值。

     关于使用位域时,内存对齐及存储大小,有以下规则。

  1. 如果相邻位域字段的类型相同,且其位宽之和小于类型的sizeof大小,则后面的字段将紧邻前一个字段存储,直到不能容纳为止
  2. 如果相邻位域字段的类型相同,但其位宽之和大于类型的sizeof大小,则后面的字段将从新的存储单元开始,其偏移量为其类型大小的整数倍;
  3. 如果相邻的位域字段的类型不同,则各编译器的具体实现有差异,VC6采取不压缩方式,Dev-C++,GCC采取压缩方式;
  4. 如果位域字段之间穿插着非位域字段,则不进行压缩;
  5. 整个结构体的总大小为最宽基本类型成员大小的整数倍。数据对齐,请参考我之前的博客https://blog.csdn.net/zgcjaxj/article/details/105929486

参考  https://blog.csdn.net/sty124578/article/details/79456405

#include <iostream>
using namespace std;
struct Data
{
	unsigned int  year ;  
	unsigned char month;
	unsigned char day;   
};

struct Data_1
{
	unsigned int year  :23;  
	unsigned int month :4; //range: 1-12
	unsigned int day   :5; //range: 1-31  
};

struct TEST
{
    bool a;
    bool b;
    bool c;
    bool d;
    bool e;
    bool f;
    bool g;
    bool h;
};

struct TEST_1
{
    bool a:1;
    bool b:1;
    bool c:1;
    bool d:1;
    bool e:1;
    bool f:1;
    bool g:1;
    bool h:1;
};

struct pack
{
	unsigned a:12;  // unsigned int,省略了int
	unsigned  :20;//该位域成员不能使用,用于填充
	unsigned c:6;   
};

int main(int argc, char** argv)
{
	cout<< "sizeof Data = "<<sizeof(Data)<<endl;
	cout<< "sizeof Data_1 = "<<sizeof(Data_1)<<endl;
	cout<< "sizeof TEST = "<<sizeof(TEST)<<endl;
	cout<< "sizeof TEST_1 = "<<sizeof(TEST_1)<<endl;

	pack  t_1;
	t_1.c = 100; // 7'b1100100, exceed 6bit,overflow, will truncate
	cout<< "sizeof pack = "<<sizeof(pack)<<endl;
	cout<< "t_1.c = "<<dec<<t_1.c<<endl;
	return 0;
}

result :

sizeof Data = 8

sizeof Data_1 = 4

sizeof TEST = 8

sizeof TEST_1 = 1

sizeof pack = 8

t_1.c = 36

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

123axj

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值