Sword 位域知识点

有些数据在存储时并不需要占用一个完整的字节,只需要占用一个或几个二进制位即可。
例如开关只有通电和断电两种状态,用 01 表示足以,也就是用一个二进位。
正是基于这种考虑,C语言又提供了一种叫做位域的数据结构。
在结构体定义时,我们可以指定某个成员变量所占用的二进制位数(Bit),这就是位域。请看下面的例子:
struct bs{
    unsigned m;
    unsigned n: 4;
    unsigned char ch: 6;
};
:后面的数字用来限定成员变量占用的位数。成员 m 没有限制,根据数据类型即可推算出它占用 4 个字节(Byte)的内存。
成员 n、ch 被:后面的数字限制,不能再根据数据类型计算长度,它们分别占用 46 位(Bit)的内存。
C语言标准还规定,只有有限的几种数据类型可以用于位域。
在 ANSI C 中,这几种数据类型是 int、signed int 和 unsigned intint 默认就是 signed int);到了 C99,_Bool 也被支持了。 但编译器在具体实现时都进行了扩展,额外支持了 char、signed char、unsigned char 以及 enum 类型,
所以上面的代码虽然不符合C语言标准,但它依然能够被编译器支持。
位域的存储
C语言标准并没有规定位域的具体存储方式,不同的编译器有不同的实现,但它们都尽量压缩存储空间。

位域的具体存储规则如下:
1) 当相邻成员的类型相同时,如果它们的位宽之和小于类型的 sizeof 大小,那么后面的成员紧邻前一个成员存储,
直到不能容纳为止;如果它们的位宽之和大于类型的 sizeof 大小,那么后面的成员将从新的存储单元开始,其偏移量为类型大小的整数倍。 2) 当相邻成员的类型不同时,不同的编译器有不同的实现方案,GCC 会压缩存储,而 VC/VS 不会。
/* 位域与结构体内存对齐 */
#include <stdio.h>
#include <stdlib.h>

struct Student
{
    char c;
    unsigned int      no;
    unsigned char     i : 1;
    unsigned char     j : 1;
    unsigned char     k : 6;
    unsigned char     m : 2;
};

/*
说明: i,j,k三个属性占用一个 unsigned char 大小
m占用一个 unsigned char 大小
 
*/

void test()
{
    printf("----size[%d]-------
", sizeof(Student));    //占用12字节大小
}

int main()
{
    test();
    getchar();
    return 0;
}
原文地址:https://www.cnblogs.com/zhanggaofeng/p/12722848.html