位域操做

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

uintptr_t indexed           : 1;

 

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

 

一. 声明测试

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

 

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

 

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

  

二. 基本原则spa

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

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

 

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

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

 

 

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

 

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位几十符号位,也是数值位

相关文章
相关标签/搜索