位域的宽度

128 阅读2分钟

背景

在 C 语言中,位域的宽度指的是用于存储位域成员的二进制位数。它定义了一个位域成员所占用的位数,限制了该成员可以表示的取值范围。

定义方式

位域的宽度可以使用冒号 : 后面的数字来指定。这个数字表示了位域成员的位数,即所需的二进制位数。

小小代码

例如,

  • uint8_t command: 2; 中的 2 表示 command 位域成员的宽度为 2 位,因此该成员只能存储 2 位二进制数。
  • uint8_t checksum: 8; 中的 8 表示 checksum 位域成员的宽度为 8 位,可以存储 8 位二进制数。

指定位域的好处

通过指定位域的宽度,我们可以有效地控制结构体成员所占用的内存空间,并限制它们可以表示的取值范围。这对于在嵌入式系统或需要节省内存的环境中非常有用。但需要注意的是,位域的宽度不能超过其所属数据类型的位数,否则行为将是未定义的。


我来研究一下

例子

按照位域宽度定义 DataPacket


typedef struct {
    uint8_t header;
    uint8_t command: 2;
    uint8_t speed: 2;
    uint8_t pressure: 2;
    uint8_t alarm: 2;
    uint8_t clear: 2;
    uint8_t checksum: 8;
} DataPacket;

没有指定位域的宽度DataPacket2


typedef struct {
    uint8_t header;
    uint8_t command;
    uint8_t speed;
    uint8_t pressure;
    uint8_t alarm;
    uint8_t clear: 2;
    uint8_t checksum;
} DataPacket2;

使用sizeof 比较大小

std::cout << "指定位域的宽度: DataPacket  size is  :" << sizeof(DataPacket) << std::endl;
std::cout << "没有指定位域的宽度DataPacket2 size is :" << sizeof(DataPacket2) << std::endl;
  • 结果

指定位域的宽度: DataPacket size is :4

没有指定位域的宽度DataPacket2 size is :7

完整代码


typedef struct {
    uint8_t header;
    uint8_t command: 2;
    uint8_t speed: 2;
    uint8_t pressure: 2;
    uint8_t alarm: 2;
    uint8_t clear: 2;
    uint8_t checksum: 8;
} DataPacket;

typedef struct {
    uint8_t header;
    uint8_t command;
    uint8_t speed;
    uint8_t pressure;
    uint8_t alarm;
    uint8_t clear: 2;
    uint8_t checksum;
} DataPacket2;

uint8_t calculateChecksum(const DataPacket *packet) {
    uint8_t checksum = packet->command + packet->speed + packet->pressure + packet->alarm + packet->clear;
    return checksum;
}

/**
 *
 * @param packet
 * @param command  命令
 * @param speed
 * @param pressure
 * @param alarm
 * @param clear
 */
void
packDataPacket(DataPacket *packet, uint8_t command, uint8_t speed, uint8_t pressure, uint8_t alarm, uint8_t clear) {
    const uint8_t MASK = 0x03;
    packet->header   = 0xAA;
    packet->command  = command & MASK;
    packet->speed    = speed & MASK;
    packet->pressure = pressure & MASK;
    packet->alarm    = alarm & MASK;
    packet->clear    = clear & MASK;
    packet->checksum = calculateChecksum(packet);
}


int main() {
    std::cout << "指定位域的宽度: DataPacket  size is  :" << sizeof(DataPacket) << std::endl;
    std::cout << "没有指定位域的宽度DataPacket2 size is :" << sizeof(DataPacket2) << std::endl;
    return 0;
}