结构体中冒号的含义及用法

文章转自:https://www.cnblogs.com/programmer-home/p/13207403.html 这个文章作者的其它c/c++/linux文章也值得看一看。

一、引入
结构体再熟悉不过了,一般我们定义一个结构体会这么写

复制代码

struct tagStudent {
    unsigned int Id;
    unsigned int age;
    char sex[12];
    char name[50];
}

复制代码

这便是一个完整的结构体定义,其内部各成员有着严格的对齐机制(关于结构体对齐机制,网上文章很多)。
      了解C语言结构体对齐机制的人都知道,结构体内部存在一定的内存空间浪费。并且在有些场景下,数据存储时并不需要占用一个完整的字节,而只需占几个或一个二进制位(即bit位)即可。例如在存放一个开关量时,只有0和1两种状态,用一位二进位即可。再例如上述结构体定义中,在32位机器下,unsigned int 类型的成员age占据了4个字节,因此年龄age的取值范围为0 ~ 4294967295,而现实中一个人的年龄往往0 ~ 150之间是绝对够用了,这就造成了内存空间浪费。有的人或许会说可以将age定义为 unsigned short,32位机器unsigned short取值范围是0 ~ 65536,依旧有很多无效内存使用不上。

       针对以上情况,为了节省存储空间并使处理简便,C语言又提供了一种数据结构,称为“位域”或“位段”。所谓“位域”是把一个字节中的二进位划分为几个不同的区域,并说明每个区域的位数。每个域有一个域名,允许在程序中按域名进行操作。这样就可以把几个不同的对象用一个字节的二进制位域来表示。
      之所以提出位域,就是由于某些信息的存储只需要几个bit位就可以,而不需要一个完整的字节(8个bit位),同时也是为了节省存储空间和方便处理。

二、位域的表示方法
位域的表示方法为:
struct 位域结构体名 {
      类型 位域成员名:  位域长度
}
例如:

复制代码

struct tagStudent {
    unsigned int Id: 2;
    unsigned int age: 2;
    char sex[12]: 5;
    char name[50]: 7;
}

复制代码

该结构体整个占用2+2+5+6=15个bit位,共15%8+1=2个字节。

三、位域的使用
位域的使用和结构成员的使用相同,其一般形式为:位域变量名·位域名。位域允许用各种格式输出。

复制代码

#include "stdio.h"

int main()
{
    struct tagStudent {
        unsigned int Id: 1;
        unsigned int age: 3;
        unsigned int cla: 5;
    } Student, *pStudent;
    
    Student.Id = 1;
    Student.age = 7;
    Student.cla = 15;
    printf("%d %d %d\n", Student.Id, Student.age, Student.cla);
   
    pStudent = &Student;
    pStudent->Id = 0;
    pStudent->age &= 3;
    pStudent->cla |= 15;
    printf("%d %d %d\n", pStudent->Id, pStudent->age, pStudent->cla);

    return 0;
} 

复制代码

上述结构体成员中,Id占1个比特位,取值范围0、1;age占3个比特位,取值范围0~8;cla占5个比特位,取值范围0~32。该结构体总共占9个比特位,2个字节。

四、注意事项
1、一个位域必须存储在同一个字节中,不能跨两个字节。
若一个字节所剩空间不够存放另一位域时,应从下一单元起存放该位域。例如:

struct bs {   
   unsigned a: 4   
   unsigned b: 3   
   unsigned c: 4   /* 从下一字节开始存放 */      
}  

在这个位域定义中,a占第一字节的4位,b占第一字节的3位,此时第一个字节还剩1位。但接下来的c需要占4位,显然第一个字节不够了,这时c从第二字节开始占4个字节,注意不存在c先把第一个字节剩下的1位占了,再从第二个字节占3位。

2、由于位域不允许跨两个字节,因此位域的长度不能大于一个字节的长度,也就是说不能超过8位二进位。例如下面的定义非法:

struct bs {   
   unsigned a: 10  /* 10大于一个字节长度,非法 */    
   unsigned b: 3         
}

3、位域可以无位域名,这时它只用来作填充或调整位置。无名的位域是不能使用的。

复制代码

struct bs {   
   int a: 1   
   int : 3   /* 这3个二进制位不能使用 */   
   int b: 3   
   int c: 2   
}; 

复制代码

4、如果位域的位域长度为0表示是个空域,同时下一个域应当从下一个字节单元开始存放。

复制代码

struct bs {   
   unsigned a: 4   
   unsigned : 0    /* 空域 */   
   unsigned b: 4   /* 从下一单元开始存放 */   
   unsigned c: 4   
}

复制代码

5、位域的本质上就是一种结构体类型,不同的是其成员是按二进制位来分配的。

  • 16
    点赞
  • 59
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值