不常见的知识-位段

101 阅读3分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第12天,点击查看活动详情

大家好,我是芒果,一名非科班的在校大学生。对C/C++、数据结构、Linux及MySql、算法等领域感兴趣,喜欢将所学知识写成博客记录下来。 希望该文章对你有所帮助!如果有错误请大佬们指正!共同学习交流

作者简介:

位段

什么是位段

位段的声明和结构是类似的,但是有两点不相同

  • 1.位段的成员必须是int unsigned int(size_t),signed int,char (即为整形家族的类型)

  • 2. 位段的成员名后面有一个冒号和一个数字(表示占多少比特位)


如:

struct A
{
    int a:2;
    int b:5;
    int c:10;
    int d:30;
};
//此时A就是一个位段类型
int main()
{
    printf("%d\n",sizeof(struct A));//8
}

为什么位段类型A的大小为8?

位段的位:二进制位

2+5+10+30 = 47bit ->6byte即可保存,为什么要8byte呢?

我们要知道位段的内存分配!

image-20220310222700851


位段的内存分配

  • 1.位段的成员可以是 int unsigned int signed int 或者是 char (属于整形家族)类型
    1. 位段的空间上是按照需要以4个字节( int )或者1个字节( char )的方式来开辟的。
    1. 位段涉及很多不确定因素,位段是不跨平台的,注重可移植的程序应该避免使用位段。

int类型一次开辟4个字节,不够保存下一个成员则再开4个字节,char类型一次开辟1个字节,不够保存下一个成员则再开辟1个字节


所以上述:

struct A
{
    int a:2;
    int b:5;
    int c:10;
    int d:30;
};

image-20220310222712863


举例子:

struct S
{
    char a:3;
    char b:4;
    char c:5;
    char d:4;
};
int main()
{
    struct S s= {0};
    s.a = 10;
    s.b = 12;
    s.c = 3;
    s.d = 4;
    return 0;
}
//空间是如何开辟的?

假设从左到右使用空间,剩下的空间不够保存下一个成员,则再开辟下一个空间

image-20220310222726579


image-20220310222801430


此时对应的16进制位:620304

image-20220310222811675

验证:

初始化:

image-20220310222838076

s只占3个字节

赋值后:

image-20220310222847721

对应16进制结果确实为 :620304


VS下位段内存空间存放规则:

  • 从右边向左边使用空间,但如果左边空间不够保存下一个成员,则再开辟下一个空间,原来的空间浪费掉

位段不可以使用offsetof()计算位段成员与起始位置的偏移量

位段的跨平台性

  • 1.int位段被当成有符号数还是无符号数是不确定的
  • 2.位段中最大位的数目不能确定(16位机器最大16,2位机器最大32)
struct A
{
  int a :2;
  int b:5;
  int c :30; 	//err
};
//16位机器, int占2个字节-16位  
//c要占位30 > 16,错误
  • 位段中的成员在内存中从左向右分配还是从右向左分配尚未定义
  • 当一个结构包含两个位段,第二个位段成员所占位比较大,无法容纳于第一个位段剩余的位时,是舍弃剩余的位还是利用,是不确定的

总结:

跟结构体相比,位段同样达到同样的效果,但是可以很好的节省空间,但是又跨平台问题


位段的应用

image-20220310222923493

枚举比结构体更节省空间