C++位域

看到本站上面关于位域的博客不少,但是真正说得清楚的、说得对的却好像真没有,本人在查阅了一些较为官方的文件之后,发表一下对于位域的解释。

位域

声明具有以位为单位的明确大小的类数据成员。相邻的位域成员可以打包成共享和跨过各个字节。

1. 语法

declarator:constant-expression

declarator是在程序中访问成员的名称。 它必须是整型类型(包括枚举类型)。

constant-expression指定结构中成员所占据的位数。 匿名位字段(即没有标识符的位字段成员)可用于填充。

Note:宽度为 0 的未命名位域强制将下一个位域与下一个类型边界对齐,其中类型是成员的类型。

2. 解释

关于上述的语法解释如下:

struct S
{
    uint32_t a : 7;    // 变量a占据uint32_t中的连续7个bit
    uint32_t b : 3;    // 变量b占据uint32_t中的连续3个bit
    uint32_t : 4;      // 占位uint32_t中的连续4个bit(但不能使用)
    uint32_t : 0;      // 占位所在的uint32_t中剩下的所有bit(但不能使用)
    uint32_t c : 0;    // 不符合语法规则,位数为0必须使用无名位域
};

3. 占位

占位规则如下:

  1. 当相邻成员的类型相同时,如果它们的位宽之和小于类型的sizeof大小,那么后面的成员紧邻前一个成员存储,直到不能容纳为止;如果它们的位宽之和大于类型的sizeof大小,那么后面的成员将从新的存储单元开始。
  2. 无名位域如果是0占位,则以所在的类型大小内全部占位;如果是非0占位,和有名位域占位一样,只是不能使用。

上面说的是什么意思呢?
解释一下:

struct S1
{
    uint16_t a : 7;    // 变量a占据uint16_t中的连续7个bit
    uint16_t b : 3;    // 变量b占据uint16_t中的连续3个bit
    uint16_t c : 5;    // 变量c占据uint16_t中的连续5个bit
    /*
    根据第一个规则的前半句话:
    现在的类型相同且相邻,所有的位宽之和为7+3+5=15,小于类型的sizeof(uint16_t)=16。
    因此会直接都紧密相接,在内存中的状态如下:
    |* * * *|* * * *|* * * *|* * * *|
    |a a a a|a a a b|b b c c|c c c *|
    所以sizeof(S1)=2
    */
};

struct S2
{
    uint16_t a : 7;    // 变量a占据uint16_t中的连续7个bit
    uint16_t b : 3;    // 变量b占据uint16_t中的连续3个bit
    uint16_t c : 8;    // 变量c占据uint16_t中的连续8个bit
    /*
    根据第一个规则的后半句话:
    现在的类型相同且相邻,所有的位宽之和为7+3+8=18,大于类型的sizeof(uint16_t)=16,
    因此会尽量向前靠齐,而c会从类型的下一个开始,且紧密相接,在内存中的状态如下:
    |* * * *|* * * *|* * * *|* * * *||* * * *|* * * *|* * * *|* * * *|
    |a a a a|a a a b|b b * *|* * * *||c c c c|c c c c|* * * *|* * * *|
    所以sizeof(S2)=4
    */
};

struct S3
{
    uint16_t a : 7;    // 变量a占据uint16_t中的连续7个bit
    uint16_t : 0;      // 剩下全部占位
    uint16_t c : 8;    // 变量c占据uint16_t中的连续8个bit
    /*
    根据第二个规则的前半句话:
    现在的类型相同且相邻,从a开始是7个bit;到下一个位数是0,表示剩下全部占位,
    因为第8bit是在上一个变量a的同一个uint16_t内,所以剩下的16-7=9个bit全部占位;
    c从新的一个uint16_t开始,在内存中的状态如下:
    |* * * *|* * * *|* * * *|* * * *||* * * *|* * * *|* * * *|* * * *|
    |a a a a|a a a *|* * * *|* * * *||c c c c|c c c c|* * * *|* * * *|
    所以sizeof(S3)=4
    */
};

struct S4
{
    uint16_t a : 7;    // 变量a占据uint16_t中的连续7个bit
    uint16_t : 5;      // 往后占位7个bit
    uint16_t b : 2;    // 变量b占据uint16_t中的连续2个bit
    uint16_t c : 8;    // 变量c占据uint16_t中的连续8个bit
    /*
    根据第二个规则的后半句话:
    现在的类型相同且相邻,从a开始是7个bit;到下一个位数是5,表示占用接下来的5个bit;
    b的位数是2位,因为7+5+2=14,一个uint16_t够用,所以紧接着排列;
    c的位数是8位,因为7+5+2+8=22,不够一个uint16_t来使用,
    因此会从新的一个uint16_t开始,在内存中的状态如下:
    |* * * *|* * * *|* * * *|* * * *||* * * *|* * * *|* * * *|* * * *|
    |a a a a|a a a *|* * * *|b b * *||c c c c|c c c c|* * * *|* * * *|
    所以sizeof(S4)=4
    */
};


参考:

  1. https://zh.cppreference.com/w/cpp/language/bit_field
  2. https://learn.microsoft.com/zh-cn/cpp/cpp/cpp-bit-fields?view=msvc-170
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值