位域

一、基本概念

1.1 位域的概念

结构体中的冒号表示位域,如:

struct bit_struct
{
    unsigned int  bit1:10;
    unsigned int  bit2:8;
    unsigned int  bit3:14;
} data1; // sizeof data1 = 4

struct bit_struct
{
    unsigned int  bit1:10;
    unsigned int  bit2:8;
    unsigned int  bit3:16;
} data2; // sizeof data2 = 8

位域出现的原因是由于某些信息的「存储表示」只需要几个 bit 位就可以表示,而不需要一个完整的字节,同时也是为了节省存储空间和方便处理。

1.2 说明

  1. 位域必须存储在同一个类型中,不能跨类型,同时也说明位域的长度不会超过所定义类型的长度。如果一个定义类型单元里所剩空间无法存放下一个域,则下一个域应该从下一单元开始存放。
    如 data2,所定义的类型是
    unsigned int
    类型,一共 32 位,bit1 和 bit2 用掉了 18bit,还剩下
    \(32-18=14bit\)
    ,这时要存储一个 16bit 的位域元素 bit3,那么这个元素就只能从下一个
    unsigned int
    类型的单元开始而不会在前面一个
    unsigned int
    类型中占 14bit 后面的 unsigned int 类型中占 2bit。

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

  3. 使用无名的位域来作为填充和调整位置,切记该位域是不能被使用的。

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

二、代码理解

#include <stdio.h>
#include <string.h>

struct bit_struct_1
{
    unsigned int  bit1:10;
    unsigned int  bit2:8;
    unsigned int  bit3:14;
} data1; // sizeof data1 = 4

struct bit_struct_2
{
    unsigned int  bit1:10;
    unsigned int  bit2:8;
    unsigned int  bit3:16;
} data2; // sizeof data2 = 8


/*
 0001 1001 0010 1010 1011 0011 0100 6666661 0101 1101 0110 1100 0666666 6666660 1000 1011
 ————————— ————————— ————————— ————————— ————————— ————————— ————————— —————————
    19        2A        B3        4F         5D        6C       8E        9B
    高 <-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·- 低
*/
int main()
{
    unsigned long long ullNum = 0x192AB34F5D6C7E8B;
    memcpy(&data1, (void *)&ullNum, sizeof(data1));
    memcpy(&data2, (void *)&ullNum, sizeof(data2));

    printf("data1 size is %d\n", sizeof(data1));  /* size is 4 */
    printf("[1] bit1 : %u\n", data1.bit1);          /* 651  --> 1010001011 */
    printf("[1] bit2 : %u\n", data1.bit2);          /* 31   --> 00066666611 */
    printf("[1] bit3 : %u\n", data1.bit3);          /* 5979 --> 01066666601011011 */

    puts("------------------------");
    printf("data2 size is %d\n", sizeof(data2));  /* size is 8 */
    printf("[2] bit1 : %u\n", data2.bit1);          /* 651   --> 1010001011 */
    printf("[2] bit2 : %u\n", data2.bit2);          /* 31    --> 00066666611 */
    printf("[2] bit3 : %u\n", data2.bit3);          /* 45903 --> 1011001101006666661 */

    return 0;
}

上述代码中我们定义了一个 8B 的 ullNum,其二进制表示如下图所示:

image-20240309161334183

从低字节到高字节分别分配给 bit1、bit2、bit3 :

image-20240309162313180

参考资料

标签: none

添加新评论