第三课:结构体中位字段的含义及使用方法

功能描述:结构体中位字段的含义及使用方法

一、结构体中的位字段

字段的类型应为整型或枚举,接下来是冒号,冒号后面是一个数字,它指定了使用的位数。可以使用没有名称的字段来提供间距。每个成员都被称为位字段。

位字段通过一个结构声明来建立,该结构声明位每个字段提供标签,并确定该字段的宽度。

struct torgle_register
{
    unsigned int SN : 4;          // 4位表示SN,最大值为二进制1111
    unsigned int : 4;             // 4位未使用
    bool goodIn : 1;              // 1bit
    bool goodTorgle : 1;          // 1bit
};

注意:位字段赋值不能超过其表示的范围,如SN 最大赋值不超过 15(即 1111)。

二、位字段的结构体所占的字节数

结构体存储变量时地址要求对齐

以 struct ABCD 为例:

struct ABCD
{
    char A;
    short B;
    int C;
    double D;
};

(1) 找出结构体中所有成员中占用字节数最多的那个成员类型,它占用的字节数即为对齐的字节数,结构体 ABCD 中成员 D 的类型位 double,占用 8 个字节,则这个结构体为 8 字节对齐。

(2) 按上述字节对齐,从上往下依次存储成员变量,如果存储的成员字节总数大于对齐字节数,则上一对齐字节剩余部分补 0,该成员存到下一个对齐字节的内存中上述中 A、B、C 加一起 7 字节,则一个 8 字节内存够用,那么 sizeof(ABCD) 则为 16,此处 A、B、C 占用一个 8 字节,D 占用一个 8 字节;如果是 int A,则 sizeof(ABCD) 则为24,此处 A、B 占用一个 8 字节,C 占用一个 8 字节,D 占用一个 8 字节。

(3) 对于含位字段的结构体,同种类型的位字段可以依次排列,不同类型的位字段不能合并存储,必须占用当前类型的字节数空间,剩余部分填充0

同种类型的位字段可以依次排列,如下:

struct ABCD
{
    unsigned int A : 4;            //4位表示A,最大值为二进制1111
    unsigned int B : 4;
    short C : 5;
    char D : 3;
};

按 (1) (2) 的方法确定 ABCD 的对齐方式为 4 字节对齐,按 (3) 的方法则 A、B 占用一个 4 字节空间,C、D 占用一个 4 字节空间,其中 C 占用 2 字节空间,D 占用 1 字节空间,因此 sizeof(ABCD) 为 8。

不同类型的位字段不能合并存储,如下:

struct ABCD
{
    char A : 1;
    short B : 1;
    int C : 1;
    long long D : 1;
};

ABCD 对齐方式为 8 字节对齐,A、B、C 共占用一个 8 字节空间,D 占用一个 8 字节空间,其中A 占用 1 个字节,B 占用 2 个字节,C 占用 4 字节。

struct ABCD
{
    short A : 5;
    short B : 11;
    short C : 9;
    short D : 7;
};

ABCD 对齐方式为 2 字节对齐,A、B刚好占用 2 字节,C、D 刚好占用 2 字节,因此 sizeof(ABCD) 为 4。

强制设置结构体的字节对齐方式

有时我们为了简化成员变量的存取,特别是在 UDP 或者 TCP 通信时,收发数据不一致时,可能就是字节对齐方式导致的。因此,我们可以采用 #pragma pack(push) 、#pragma pack(1)  #pragma pack(pop) 的方式设置字节对齐方式,一般设置为单字节对齐

#pragma pack(push)                // 保存默认字节对齐方式
#pragma pack(1)                   // 设置单字节对齐

struct ABCD
{
    char A;
    short B;
    int C;
    double D;
};

#pragma pack(pop)                // 恢复默认字节对齐方式

ABCD 对齐方式为单字节对齐,A 占用 1 字节, B 占用 2 字节,C 占用 4 字节,D 占用 8 字节,因此 sizeof(ABCD) 为 15。

四、测试验证

在 Qt 中测试验证代码如下:

#include <QApplication>
#include <QDebug>

#pragma pack(push)
#pragma pack(1)

struct torgle_register
{
    unsigned int A : 4;		         //4位表示A,最大值为二进制1111
    unsigned int B : 4;
    short C : 5;
    char D : 3;
};

struct ABCD
{
    char A;
    short B;
    int C;
    double D;
};

//struct ABCD
//{
//    unsigned int A : 4;            //4位表示A,最大值为二进制1111
//    unsigned int B : 4;
//    short C : 5;
//    char D : 3;
//};

//struct ABCD
//{
//    char A : 1;
//    short B : 1;
//    int C : 1;
//    long long D : 1;
//};

//struct ABCD
//{
//    short A : 5;
//    short B : 11;
//    short C : 9;
//    short D : 7;
//};

#pragma pack(pop)

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    qDebug() << sizeof(torgle_register) << sizeof(ABCD);

    return 0;
}
  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Yann@

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

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

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

打赏作者

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

抵扣说明:

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

余额充值