ETJava Beta | Java    注册   登录
  • 搜索:
  • 位段 -- 内存布局详解-浅谈C语言

    发表于      阅读(1)     博客类别:Crawler     转自:https://www.cnblogs.com/DSCL-ing/p/18341951
    如有侵权 请联系我们删除  (页面底部联系我们)  

    位段

    位段的介绍

    位段(二进制位):就是按位存储

    位段(bit-field)是C语言中的一种特殊数据类型,它允许将一个字节分成几个部分,并为每个部分指定特定的位数,以便在内存中存储和访问这些部分。

    其中位段相较于结构体有两特殊点

    1. 位段的成员必须是 int unsigned int或 signed int char(整型家族) ,在C99中位段的成员也可以是其他类型
    2. 位段的成员名后跟一个冒号和数字

    位段使用示例:

    struct S
    {
        int a : 2;  //限定2个比特位
        int b : 5;  //限定5个比特位
        int c : 10; //限定10个比特位
        int d : 30; //限定30个比特位
    };
    

    位段的内存分配

    1.位段的空间上是按照需要以4个字节(int)或者1个字节(char)的方式来开辟的。(...如,int一次开辟4字节32比特位来使用,不够再开辟)
    2.位段涉及很多不确定因素,位段是不跨平台的,注重可移植的程序应该避免使用位段。(网络编程涉及,网络传输数据包,)
    (原因:没有C语言标准,各编译器有所不同。)
    位段不能大于32(32位机器),16位则不能大于16位
    不给定位段的默认为字节数

    Example

    struct S
    {
        char a : 3;
        char b : 4;
        char c : 5;
        char d : 4;
    };
    int main()
    {
        struct S s = { 0 };
        s.a = 10;// 1010 |  010
        s.b = 20;//10100 | 0100
        s.c = 3; //  011 |00011
        s.d = 4; //  100 | 0100
        return 0;
    }
    
    

    内存分配解析:

    1. VS编译器为从左往右一次申请空间,一次1个字节/8个比特位
     -----> 申请空间方向 ----> 
      0000 0000 
    
    2. 然后开始存放a的数据10(D) = 1010(B),a限制为3个比特,多出的比特会被丢弃,即最后保留数据为010(B), 
     --- vs中,每个字节内数据从右往左写入; 
    (地址)  0000 0|010
    
    3. 放好a后,开始放b = 20(D) = 10100(B),b限制为4字节,切割b,得到b = 0100(B)
     第一空间放完a后,还剩5个比特,组以容纳b,因此在从四个字节开始(从右往左数),写入b
    (地址)  0010 0010(b) 								= 22(h);
    (划分)	0 | 0 1 0 0 | 0 1 0   
    	   					b        a
    
    4. 接下来放c,c占5个比特位,显然第一个字节不够放了,因此要开辟第二个字节,然后切割c(不超过因此不用切),得到c = 011(b) ;
    (地址)  0010 0010		0000 0011
    (划分)  0 | 0 1 0 0 | 0 1 0     0 0 0 | 0 0 0 1 1   
    			 舍     b         a                  c
    
    5.接下来放d,d占4个字节,显然第2个字节不够放了,因此申请第三个字节,然后切割b,得到100(b);
    (地址)  0010 0010		0000 0011 	0000 0100
    (划分)	0 | 0 1 0 0 | 0 1 0     0 0 0 | 0 0 0 1 1     0 0 0 0 | 0 1 0 0 
    		 	 舍     b        a         舍        c                      d
    
    6.最后转换十六进制,得到
        22					   03						04   (十六进制)
    即内存显示:22 03 04
    
    7.还可能会有内存对齐,32位为 22 03 04 00 ....
    

    image-20240804165014639

    位段的跨平台问题

    1. int位段被当成有符号数还是无符号数没有规定(最高位1当成什么不确定)
    2. 位段中最大位的数目不能确定(16位机器最大为16,32位机器最大32。写成27,在16位机器会出问题
    3. 位段中的成员在内存中从左向右分配,还是从右向左分配没有规定(00001111还是11110000)
    4. 当一个结构体包含两个位段,第二个位段成员比较大,无法容纳第一个位段剩余的位时,不确定是舍弃剩余位还是利用。(按类型字节开辟的位不够放时,VS中是舍弃)

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