• 位域操作


    看runtime源码时,看到如下声明变量的,变量后分号前加冒号和数字": 数字"即为位域操作。

    uintptr_t indexed           : 1;

     

    1个字节包含8位,有些变量保存的数据不需要占用这么长的空间(比如bool类型,只有两个状态true和false, 1位就可以搞定,剩下的7位就浪费了),这就催生了“位域”结构,位域将1个字节划分成不同的区域,每个区域都有个位域名(可以理解为变量名,上边的代码中位域名为indexed),程序员可以代码通过位域名访问其中的数据。

     

    一. 声明

    
    
    类型说明符 位域名:位域长度;
    
    

     

    位域结构体,我理解是一种特殊的结构体,其成员变量都是位域,声明如下

     

    struct 位域结构名 
    {
      类型说明符 位域名:位域长度;
      类型说明符 位域名:位域长度;
      类型说明符 位域名:位域长度;
      ...
      类型说明符 位域名:位域长度;
    };

      

    二. 基本原则

    1. 位域变量的长度不能大于其类型的长度(sizeof(类型) * 8)

    变量char has_assoc的类型位char 1字节 8位,小于定义的10,所以编译器警告

     

    2.  不能用于位域字段的操作:取地址操作符&,取偏移量操作

    位域是若干位空间,是没有地址的

     

     

    3. 位域可以是无名位域,无名位域只能用作填充或调整位置,不能使用。如下图结构体S007的最后一个变量就是无名位域,无法使用

     

    4. 位域字段不能声明为类的静态成员

    5. 位域结构体的大小必须是其最长基本类型大小的整数倍(sizeof(类型) * 8)

    三. 内存分配规则

    1. 判断大小端,以我自己的机子为例,不同环境下有可能不同

     

    定义联合体U007和位域结构体S007,将U007实例u7的number赋值31,二进制为 | 0000 0000 | 0000 0000 | 0000 0000 | 0001 1111 |,根据存储原则,数值都是从高地址往低地址读,因此位域结构体S007中的位域变量是从低地址开始分配内存的,即

     

    2. 位域变量类型相同

    位域变量长度之和小于[sizeof(变量类型)*8], 则后面的位域字段将紧邻前一个字段存储, 直到不能容纳为止

    位域变量长度之和大于[sizeof(变量类型)*8], 则后面的位域字段将从下一个存储单元的起始地址处开始存放(其偏移量恰好为sizeof(变量类型)的整数倍)

     

    位域结构体S007的3个成员变量都是unfigned short类型,sizeof(unfigned short)*8 = 16位,

    a0占1位,从起始地址分配1位;

    a1占9位,a0+a1=10位,小于16位(sizeof(unfigned short)*8),因此a1在a0后连续分配9位;

    a2占15位,(a0 + a1) + a2 = 25位,大于16位,因此跳过6位,在S007起始地址偏移量为16位的地方,给a2分配15位。

    再次提醒:小端是分配内存地址时从低地址开始,但是变量的数值是从高地址往低地址读

     

    3. 位域变量类型不同时,各个编译器的具体实现有差异,VC6采取不压缩方式,GCC和Dev-C++都采用压缩方式,以下是我自己机子的处理方式

    位域结构体S007的前2个成员变量unfigned char类型(sizeof(unfigned char)*8 = 8位),后一个成员变量unfigned short(sizeof(unfigned short)*8 = 16位)

    a占2位,从起始地址分配2位;

    b占3位,a+b=5位,小于8位(sizeof(unfigned char)*8,b的类型是unfigned char),因此b在a后连续分配3位;

    c占15位,(a + b) + c = 20位,大于16位(sizeof(unfigned short)*8,c的类型是unfigned short),因此跳过11位,在S007起始地址偏移量为16位的地方,给c分配15位。

    有上图可以看出,在我的机子上,如果位域变量的类型不同,仍会进行内存压缩(如果需要跳位,判断哪个位域变量,就用该变量的类型进行偏移量对齐判断)

     4. 如果位域变量之间穿插着非位域变量, 则不进行压缩

    非位域变量也可以理解为特殊的位域变量,只不过占的位数是变量长度,即 类型 位域名 : sizeof(类型)*8

    根据规则3,则无法进行内存压缩

    位域结构体S007的第2个成员变量char tmp;是非位域变量,转成位域变量为 char tmp:8;

    a占2位,从起始地址分配2位;

    tmp占8位,a+tmp=10位,大于8位(sizeof(char)*8,tmp的类型是char),因此跳过6位,在S007起始地址偏移量为8位的地方,给tmp分配8位;

    b占3位,在tmp后给b分配3位。

    5. 上边举的例子中参数都是unsigned标识的,如果带上符号位会是什么情况呢?

    关于带符号基本类型变量在内存中存储方式,请看这里http://www.cnblogs.com/xieyajie/p/8125214.html

     

    位域结构体S008定义了2个带符号位域变量,a0占2位,a1占3位

    a0是带符号short类型,内存中保存的是补码11,首位符号位为1,负数,推出源码为11,转为十进制为-1;

    a1是带符号short类型,内存中保存的是补码001,首位符号位为0,正数,源码为001,转为十进制为1。

    如果a0只占1位会怎么样?从测试结果可以看出,这1位几十符号位,也是数值位

  • 相关阅读:
    mysql基本用法
    linux基本指令
    servlet的生命周期
    day 15 笔记
    day 14 作业
    考试二
    day 14
    day 12 zuoye
    day 13
    day 12
  • 原文地址:https://www.cnblogs.com/xieyajie/p/8110224.html
Copyright © 2020-2023  润新知