C/C++——位域的使用

  1. 位域的概念
    在结构体定义时,我们可以指定某个成员变量所占用的二进制位数(Bit),这就是位域。

    struct {
        unsigned int m;
        unsigned int n: 4;
        unsigned char ch: 6;
    }a;
    

    其中:指定了所占的内存大小,m占4字节,n占4bit,ch占6bit。
    具体哪些类型能够支持位域操作,因编译器而异,但是大部分整数类型(char,int,long)都能支持位域操作。

  2. 位域的溢出问题
    C语言标准规定,位域的宽度不能超过它所依附的数据类型的长度。通俗地讲,成员变量都是有类型的,这个类型限制了成员变量的最大长度,:后面的数字不能超过这个长度。上面的定义中,n指定的空间不超过int类型的空间大小,即32bit(4字节),ch指定的空间不超过char类型的空间大小,即8bit(1字节)。若在赋值是,超过指定空间的大小,将发生溢出,在输出时,只会截取有效的部分。

    #include <stdio.h>
    int main(){
        struct bs{
            unsigned m;
            unsigned n: 4;
            unsigned char ch: 6;
        } a; 
    
        a.m = 0xb8901c;
        a.n = 0x2d;
        a.ch = 'z';
        printf("%#x, %#x, %c\n", a.m, a.n, a.ch);
        return 0;
    }
    

    输出结果
    在这里插入图片描述
    对比输出结果,n和ch发生了变化,是因为赋值时,发生了溢出,所以最后输出只输出了有效部分,这和整数存储时发生溢出是一样的处理方式。说明一下,'z’对应的ASCII码为0x7a,截取6位有效部分变成了0x3a,对应的字符是 ‘:’ 。

  3. 位域的存储方式

    3.1结构体中定义的相邻成员的类型相同
    当结构体中定义的相邻成员的类型相同时,是奔着压缩空间的原则去的。如果各个成员的位宽之和小于他们所依附的数据类型的大小,那么会紧邻前一个成员排列,知道不能容纳为止,最后的那个不能容纳的成员将被分配到下一个相同类型的存储空间中。

    #include <stdio.h>
    
    int main(){
        struct bs
        {
            unsigned int m: 10;
            unsigned int n: 12;
            unsigned int p: 8;
        };
        printf("%d\n", sizeof(struct bs));
    
        return 0;
    }
    

    代码中结构体的成员加起来的空间是30bit小于int类型的空间大小,那么这个结构体的空间将会被压缩到一个int类型的空间大小中。
    在这里插入图片描述
    当把m指定的空间改为22时,前两个变量加起来的空间超过了32,那么编译器会为m分配一个int类型的空间,n和p加起来的空间没有超过32,编译器会这两个变量分配一个int类型的空间。
    在这里插入图片描述
    当把p指定的空间也改为22时,编译器会为这三个变量分别分配3个int类型的空间,此时,他们之间的未用到的位将无法利用,只有浪费掉。
    在这里插入图片描述
    3.2当相邻成员的类型不同时

    #include <stdio.h>
    int main(){
        struct bs{
            unsigned int m: 12;
            unsigned char ch: 4;
            unsigned int p: 4;
        };
        printf("%d\n", sizeof(struct bs));
        return 0;
    }
    

    这段代码在不同的编译器下,所占用的空间不同,在gcc下会被压缩,运行结果为4.
    在这里插入图片描述
    在VC/VS下运行结果是12。
    在这里插入图片描述
    按理说4+1+4=9,应该是9字节。为了提高寻找效率,会进行4字节内存对齐。

    3.3成员之间穿插着非位域成员,那么不会进行压缩。

    #include <stdio.h>
    int main(){
        struct bs{
            unsigned int m: 12;
            unsigned int n;
            unsigned int p: 4;
        };
        printf("%d\n", sizeof(struct bs));
        return 0;
    }
    

    在这里插入图片描述

    3.4访问位域成员
    位域成员的访问也可以通过 “ . ” 和“ -> ”访问
    在这里插入图片描述
    但是,因为位域成员往往不占用完整的字节,有时候也不处于字节的开头位置,因此使用&获取位域成员的地址是没有意义的,C语言也禁止这样做。地址是字节(Byte)的编号,而不是位(Bit)的编号。

    3.5无名位域
    位域成员可以没有名称,只给出数据类型和位宽

    struct bs{
        int m: 12;
        int  : 20;  //该位域成员不能使用
        int n: 4;
    };
    

    代码中有个成员没有名字,无法使用这部分空间,这就是无名位域,它存在的作用就是起一个占位作用,代码中因为多了个20bit的无名位域,所以这个结构体占8个字节空间。这个知识点实际应用中基本不用。

  4. 位域的应用
    位域的应用,主要在于节省空间,在定义寄存器不同位的同时,将所有变量的空间大小限制在一个依赖的类型里面。
    在这里插入图片描述
    这个结构体里面定义了一个32位寄存器的所有位,所有变量的空间加起来只有一个int类型变量的大小。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值