C#中的位操作:BitVector32结构

http://www.cnblogs.com/mgen/archive/2011/06/25/2090265.htmlNET(C#)中的位操作:BitVector32结构

BitVector32结构体位于System.Collections.Specialized命名空间内,相对.NET中另外一个位容器BitArray,他的优点是速度快,占用空间小,并可以存储小数字。他内部用一个32位的整数来存储数据,因此只能存储32位的比特数据。

返回目录

温习位操作

在看BitVector32前,温习一下简单的位操作还是很有必要的,常见的位操作无非就是与(AND),或(OR),非(NOT)。一般情况下,将一位设置成1就是把这个为或1的操作,将一位设置成0就是把这个位与0的操作。同时或0,与1结果不变。

这样的话,比如一个8位的数据:

0000 1111

我们想把第二个0设置成1,那么把他和下面这个数进行或操作:

0100 0000

结果就是

0100 1111

第二位变成了1

还是这个数

0000 1111

如果想把最后一个1设置成0,那么把他和下面这个数进行与操作

1111 1110

结果就是

0000 1110

那么我们可以这样总结一下:

想要操作一个位,我们把其他位设置成0,把这个位设置成1,这个数就是所谓的位掩码(也称位屏蔽,MSDN里用的是位屏蔽)

那么如果想打开一个位(就是把这个位设置成1):源数据 = 源数据 OR 位掩码

如果想关掉一个位(就是把这个位设置成0):源数据 = 源数据 AND 位掩码取反

(位掩码取反就是非(NOT)操作:0变成1,1变成0  )

返回目录

BitVector32的位操作

了解了基本位操作BitVector32的理解就会简单多了。

首先BitVector32本质上用一个32位的数来表示数据,那么初始化BitVector32结构时必须制定一个最初值,用户可以传入一个int或者另一个已经存在的BitVector32来构造一个新的BitVector32.

BitVector32的Data属性返回一个int用来表示内部数据,如果用来显示BitVector32的内容,这个Data是没有意义的,因为他是十进制化的结果,这时候用BitVector32的ToString方法就可以返回有用的文字说明。

BitVector32 bits = new BitVector32(0xF);

//初始化BitVector32:设置低4位为1  0x 00 00 00 00 00 00 00 0F

Console.WriteLine(bits.Data);

//(十六进制)0xF 等于 (二进制)1111 等于 (十进制)15 所以输出15

Console.WriteLine(bits.ToString());

//输出:BitVector32{00000000000000000000000000001111} (看得出来:后四位是1)

接下来就是最重要的位操作了。

BitVector32结构体提供索引器(Indexer)可以直接通过bool对象操作BitVector32结构,索引器参数是int,这个int可不是指第几位的意思(BitArray中的索引器是第几位),而是需要一个位掩码(位屏蔽),通过这个BitVector32通过这个位掩码来操作内部比特位,来看看Reflector下BitVector32索引器的源码

struct BitVector32

{

//data 就是 BitVector32的Data属性的对应字段

public bool this[int bit]

{

get

{

return ((this.data & bit) == ((ulong)bit));

//通过数据和掩码的与操作,来将其他位清0,保留掩码的设置位

//如果操作后的结果等于掩码,很显然这是操作位就是1,返回true

//否则的话,返回false

}

set

{

if (value)

{

this.data |= (uint)bit;

//数据 = 数据 OR 掩码,将指定位设置成1

}

else

{

this.data &= (uint)~bit;

//数据 = 数据 AND 掩码取反,将指定位设置成0

//C# 取反位操作运算符:~

}

}

}

}

上面代码我加了注释,可以看到,BitVector32的位操作就是利用普通位掩码的操作。

好了那么用BitVector32索引器操作其实就是定义好位掩码,接着取回信息或者赋值就可以了。

//注意using System.Collections.Specialized;

int mask1 = 1;

//掩码代表最后一位:二进制表示:0...0001

int mask2 = 4;

//掩码代表倒数第三位:二进制表示:0...0000100

BitVector32 bits = new BitVector32(-1);

//-1补码:1...1111

//设置BitVector32全部为1

Console.WriteLine(bits);

Console.WriteLine("设置最后一位和倒数第三位位0");

bits[mask1] = bits[mask2] = false;

Console.WriteLine(bits);

Console.WriteLine("设置倒数第三位为1");

bits[mask2] = true;

Console.WriteLine(bits);

输出:

BitVector32{11111111111111111111111111111111}

设置最后一位和倒数第三位位0

BitVector32{11111111111111111111111111111010}

设置倒数第三位为1

BitVector32{11111111111111111111111111111110}

返回目录

CreateMask方法

BitVector还有一个CreateMask方法,他的作用就是方便用户定义位掩码。

CreateMask(无参数):返回第一个位(最低位)的位掩码,那么就是0…00001,十进制的话就是1

CreareMask(int):首先判断一直位掩码的合法性,并返回向左移1位的结果。

参考CreateMask的源代码:

public static int CreateMask(int previous)

{

if (previous == 0)

{

return 1;

}

if (previous == -2147483648) //这个数等于Int32.MinValue 二进制是100...0,无法再向左移位,因此异常

{

throw new InvalidOperationException(SR.GetString("BitVectorFull"));

//抛出异常

}

return (previous << 1); //向左移1位

}

当然如果你掌握了上述位操作和位掩码的概念,我个人感觉CreateMask有点多此一举呵呵,我们就直接用MSDN的例子(我改了改注释)

// 初始化BitVector32:全部0

BitVector32 myBV = new BitVector32(0);

// 创建最低位的掩码,然后陆续创建倒数第二位,倒数第三位……倒数第五位的掩码

int myBit1 = BitVector32.CreateMask();

int myBit2 = BitVector32.CreateMask(myBit1);

int myBit3 = BitVector32.CreateMask(myBit2);

int myBit4 = BitVector32.CreateMask(myBit3);

int myBit5 = BitVector32.CreateMask(myBit4);

Console.WriteLine("最初值:               \t{0}", myBV.ToString());

// 设置倒数第三位为1

myBV[myBit3] = true;

Console.WriteLine("myBit3 = TRUE          \t{0}", myBV.ToString());

// 将掩码加起来,同时设置两个位

myBV[myBit4 + myBit5] = true;

Console.WriteLine("myBit4 + myBit5 = TRUE \t{0}", myBV.ToString());

myBV[myBit1 | myBit2] = true;

Console.WriteLine("myBit1 | myBit2 = TRUE \t{0}", myBV.ToString());

输出:

最初值:                 BitVector32{00000000000000000000000000000000}

myBit3 = TRUE           BitVector32{00000000000000000000000000000100}

myBit4 + myBit5 = TRUE  BitVector32{00000000000000000000000000011100}

myBit1 | myBit2 = TRUE  BitVector32{00000000000000000000000000011111}

如果你手动输出上面例子中的myBit1-5的值,其实就是我们上面讲到的倒数一到五位的掩码值。

返回目录

使用BitVector32.Section来存储小整数

BitVector32的最后一项功能就是存储小整数,这种情景很不常见,可能会用在存储空间极低的设备上。打个比方就是:比如你存3个数,一个在0-10之内,剩下两个在0-300之内。其实一般情况下,我们用3个int存就可以。如果省空间的话,用一个byte,两个short。如果还想省空间的话,用一个int存就可以,那么这个时侯,就需要BitVector32.

使用BitVector32的静态方法CreateSection返回一个BitVector32.Section结构体。CreateSection需要一个int来指定所存区域的最大整数值(注意只能存0-这个最大值),BitVector32会根据这个最大值来分配所占位长度。接着后续CreateSection函数的调用必须传入之前的Section,因为Section的创建是建立在前面Section没有占用的空闲位。

同时,BitVector32还拥有另一个重载的索引器专门针对Section来进行操作。

代码示例:

//初始化全部0

BitVector32 bits = new BitVector32(0);

//创建Section

BitVector32.Section sec1 = BitVector32.CreateSection(10);

BitVector32.Section sec2 = BitVector32.CreateSection(300, sec1);

BitVector32.Section sec3 = BitVector32.CreateSection(300, sec2);

//设置每一个Section,注意值要在定义范围之内

bits[sec1] = 9;

bits[sec2] = 123;

bits[sec3] = 289;

Console.WriteLine("Section 1值:{0}", bits[sec1]);

Console.WriteLine("Section 2值:{0}", bits[sec2]);

Console.WriteLine("Section 3值:{0}", bits[sec3]);

//来看看32位的空间用的怎么样

Console.WriteLine(bits);

/*

* 这句输出:BitVector32{00000000001001000010011110111001}

* 前面还有很多0,那么应该还可以存一些数据,果然省空间啊,呵呵

* */

输出:

Section 1值:9

Section 2值:123

Section 3值:289

BitVector32{00000000001001000010011110111001}

作者:Mgen
出处:www.cnblogs.com/mgen

C#中的位操作:BitVector32结构相关推荐

  1. 位操作:BitVector32结构 z

    目录 温习位操作 BitVector32的位操作 CreateMask方法 使用BitVector32.Section来存储小整数 BitVector32结构体位于System.Collections ...

  2. Nature :全球表层土壤中微生物组的结构和功能

    文章目录 Structure and function of the global topsoil microbiome 全球表层土微生物组群落结构和功能 热心肠日报导读 摘要 正文 **图1. 真菌 ...

  3. Linux中表示“时间”的结构体和相关函数

    转载于:http://blog.chinaunix.net/uid-25909722-id-2827364.html Linux中表示"时间"的结构体和相关函数 2011-09-1 ...

  4. 网页优化中,网站页面结构该注意什么?

    网站页面结构即网页内容布局,网站页面结构的创建就是要对网页的内容进行规划布局,合理的网站页面结构总是很受搜索引擎蜘蛛的欢迎,网站页面结构也能直接影响页面的用户体验及相关性,还能影响网站整体结构及页面被 ...

  5. class字节码文件中的常量池结构详解

    文章目录 前言 方法区 常量池基本结构 JVM 所定义的11种常量 常量池元素的复合结构 常量池的结束位置 常量池元素总数量 第一个常量池元素 父类常量 变量型常量池元素 自己的学习笔记,部分节选自& ...

  6. datasg中数据的存储结构

    datasg中数据的存储结构 转载于:https://www.cnblogs.com/LoveFishC/archive/2012/07/27/3845623.html

  7. java 组合对象_Java 中组合模型之对象结构模式的详解

    Java 中组合模型之对象结构模式的详解 一.意图 将对象组合成树形结构以表示"部分-整体"的层次结构.Composite使得用户对单个对象和组合对象的使用具有一致性. 二.适用性 ...

  8. 以下选项中python用于异常处理结构_《Python 程序设计》复习题

    目录 填空题 一.基础知识 二.序列 三.选择结构与循环结构和函数及面向对象.文件 选择题 一.Python 基础语法 二.基本数据类型 三.程序的控制结构 四.函数和代码复用 五.组合数据类型 六. ...

  9. Intellij IDEA展示类中的方法树形结构

    在intellij Idea中叫Structure(结构体),如下图: 也可以直接Alt+F7快捷键,这样默认会把Structure显示在屏幕下方,如下图操作就可以移动到右侧. 效果如下:

最新文章

  1. python输入输出流详解_输入输出流的概念
  2. 查看python安装路径-Mac查看Python安装路径和版本
  3. php钩子是啥意思,php中的钩子理解及应用实例分析
  4. 12 月机器学习新书:《可解释机器学习方法的局限》,免费下载!
  5. 大学哪些专业要学python_非计算机专业的大学生是否有必要学习Python编程
  6. mysql导入数据提前修改字段_Mysql一些导入导出数据库,添加修改字段命令_MySQL...
  7. Linux 命令(83)—— groups 命令
  8. 基础选择器之通配符选择器(CSS、HTML)
  9. 人人都是产品经理指南:技术转产品经理,从入门到放弃
  10. 《文后参考文献著录规则》
  11. Google Chrome浏览器用户数据迁移
  12. Tushare财经数据调取方法(行情数据)
  13. 解决ERROR:Local variable count defined in an enclosing scope must be final or effectively final
  14. Science重磅:颠覆教科书!科学家找到癌症发生源头,治愈肿瘤有了新思路
  15. 【量化投资】策略二(聚宽)
  16. vue实现音乐平台项目
  17. rk3288 原子操作和原子位操作
  18. 你要的能做出炫酷图表的网站来啦
  19. (1)ESP8266微信门铃
  20. cisco 3550

热门文章

  1. 文件异常与文本文件处理
  2. 读心术python_有哪些厉害的观人术读心术?
  3. html div挤下去了,HTML的div相挤现象
  4. Mysql-基础命令
  5. 将Windows7屏幕外的窗口拖回
  6. 嵌入式作业STM32采用串口DMA方式发送数据
  7. javascript之活灵活现的Array
  8. 封装一个活灵活现的原生JS排序,js按照拼音排序,js按照“数字-字符串-汉字拼音”排序,数组对象排序,数组排序微调即可
  9. 如何用coda虚拟环境分隔多个tensorflow版本
  10. Android支持百分比布局