C语言中不常见类型:位段的详解

目录

位段

        我们都知道结构体,那您是否了解位段呢?

        一、位段的定义 

        二、位段的内存分配

        三、段位赋值问题

        四、位段跨平台问题

        五、位段的运用 


位段

        我们都知道结构体,那您是否了解位段呢?

        仔细观察一下两个不一样的“结构体”,他们有什么区别呢?

        一、位段的定义 

                位段的声明和结构体是类似的,但是有两点不同:

                        1.位段的成员必须是int、unsigned int、signed int或char(char属于整型家族)类型。(一般情况下位段的成员类型都全部为int或者char类型)

                        2.位段成员的后面有一个:(冒号)和一个数字(数字表示这个成员所需内存大小,以bit为单位)。

                如上面的H就是一个位段。

        二、位段的内存分配

                位段的空间是以4个字节(位段成员是int类型)或者1个字节(位段成员是char类型)开辟的。(所以冒号后面的bit大小不会超过32bit(int类型)或8bit(char类型),具体还是要看机器(如16位机器int是2字节,32位机器int是4字节)

                如下面G这个位段:

struct G
{
	int i : 2;
	int o : 5;
	int p : 10;
	int u : 30;
};

                i占2bit,o占5bit,p占10bit,u占30bit,加起来应该是47bit,按道理6字节的空间就够存储他们了。

                可事实并非如此:

                经实践认证此位段所占空间为8字节,为什么呢?

下面我们来对此位段空间的分配进行详解:

由于此位段成员类型都是int,所以每次以4个字节(也就是32bit)为单位开辟空间:

        以小段存储为例,我们先开辟32bit的空间:

         再将只占2bit的i成员先存入: 

        接着紧按着i成员,将5bit的哦成员存入(段位没有像结构体一样的内存对齐):

 

        之后再将10bit空间的p成员存入:

        最后我们在存30bit的u成员时,发现内存只剩15bit不够用,此时我们再向空间申请4字节(int类型)的空间:

         存入30bit的p成员:

         在我们存完所有成员之后,我们发现实际存p时系统并不会再使用上面并未用完的15bit的空间,而是直接在可以存下p的新空间地方存p。

        这就最终造成了段位G所占用的空间为64bit(8字节)。

        三、段位赋值问题

                现在我们将位段赋值:

int main()
{
  unsigned char puc[4];
  struct tagPIM
  {
    unsigned char ucPim1;
    unsigned char ucData0 : 1;
    unsigned char ucData1 : 2;
    unsigned char ucData2 : 3;
  }*pstPimData;
  pstPimData = (struct tagPIM*)puc;
  memset(puc,0,4);//将数组puc的4个字节全部赋值为0
  pstPimData->ucPim1 = 2; 
  pstPimData->ucData0 = 3;
  pstPimData->ucData1 = 4;
  pstPimData->ucData2 = 5;
  printf("%02x %02x %02x %02x\n",puc[0], puc[1], puc[2], puc[3]);
  return 0;
}

 我们先来模拟展示一下位段tagPIM的存储结构:

         如图位段tagPIM的总存储大小为16bit,其中ucPim1占8bit、ucData2占3bit、ucData占2bit、ucData0占1bit。

而字符数组puc的存储结构为:

         如图char元素0、1、2、3分别占8bit,一共32bit。

        所以将puc强转为段位tagPIM指针类型时(pstPimData = (struct tagPIM*)puc),pstPimData最多可以指向puc字符数组中0和1元素大小的空间。

        当puc中所以元素都被赋值为0时:

         当pstPimData->ucPim1 = 2时,即ucPim1指针大小的空间被赋值为2时,2的二进制表示是10,puc中的元素发生如下变化:

        

        当pstPimData->ucData0 = 3时,即ucData0指针大小的空间被赋值为3时,3的二进制表示是11,可是ucData0大小只有1bit,所以舍弃前一位,puc中的元素发生如下变化:

 

        当 pstPimData->ucData1 = 4时,即ucData1指针大小的空间被赋值为4时,4的二进制表示是100,可是ucData1大小只有2bit,所以舍弃前一位,puc中的元素发生如下变化:

        当pstPimData->ucData2 = 5时,即ucData2指针大小的空间被赋值为5时,5的二进制表示是101,可是ucData2的大小正好是3bit,所以不用舍弃,puc中的元素发生如下变化:

 

         最终进行printf打印时puc【0】的值为10换为十六进制为2,puc【1】的值为101001转换为十六进制为29,puc【2】和puc【3】的值还为0。

        四、位段跨平台问题

                1.int位段被当成有符号数还是无符号数是不确定的。
                2.位段中最大位的数目不能确定。(16位机器最大16,32位机器最大32,写成27,在16位机器会出问题)。
                3.位段中的成员在内存中从左向右分配,还是从右向左分配标准尚未定义。
                4.当一个结构包含两个位段,第二个位段成员比较大,无法容纳于第一个位段剩余的位时,是舍弃剩余的位还是利用,这是不确定的。

所以说跟结构体相比位段可以达到相同的效果而且比较节省空间,但是有跨平台的问题存在。

        五、位段的运用 

        位段通常会运用在网络数据的封装(浅浅提一下~):


好了,今天的博客又要和大家说再见了,谢谢各位看官嘞!

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

1e-12

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

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

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

打赏作者

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

抵扣说明:

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

余额充值