现在的位置: 首页 > 综合 > 正文

.NET(C#):负数位域和正数位域

2012年01月14日 ⁄ 综合 ⁄ 共 1387字 ⁄ 字号 评论关闭

我们常见到的位域标志定义都是基于正数的,不过其实也可以定义成基于负数的,工作起来则和正数标志位域一样。

 

比如定义一个8位的位域,提供两个选项分别是最高位和最低位为1。然后分别以byte和sbyte作为枚举背后数据类型,则枚举应该这样声明:

[Flags]

enum a : byte

{

    //128的原码为:10000000

    High = 128,

    Low = 1

}

 

[Flags]

enum b : sbyte

{

    //-128的补码为:10000000

    High = -128,

    Low = 1

}

 

接下来根据相应的类型,把变量的全部标志都设置为1,然后判断最高位和最低位是否被开启。

//将全部标志设置为1(开启状态)

//255原码:1111 1111

var aFull = (a)255;

//-1补码:1111 1111

var bFull = (b)(-1);

 

//通过枚举仅将最高位和最低位开启

var aMask = a.High | a.Low;

var bMask = (b.High | b.Low);

 

//判断标志是否被开启

Console.WriteLine((aFull & aMask) == aMask);

Console.WriteLine((bFull & bMask) == bMask);

 

结果都会输出True。

 

事实上,完全可以把它们转换成同一个类型进行同样的位操作,比如都转换成byte类型:

static void Main(string[] args)

{

    //将全部标志设置为1(开启状态)

    //255原码:1111 1111

    var aFull = (a)255;

    //-1补码:1111 1111

    var bFull = (b)(-1);

 

    doo((byte)aFull);

    doo((byte)bFull);

}

 

static void doo(byte b)

{

    //129原码:1000 0001

    byte mask = 129;

    Console.WriteLine((b & mask) == mask);

}

 

上面代码同样会输出两个True。原因是当一个负数被强制转换成无符号数字,它背后的二进制数据会被强行塞进对应变量空间,所以从位域的角度看,没有发生任何变化。(更多关于C#强制转换的越界检查可以参考这篇文章:http://www.cnblogs.com/mgen/archive/2012/04/08/2438029.html

 

.NET 4.0新加的Enum.HasFlag方法的工作原理就是这样的,只不过它用的是无符号Long(ulong),如下图:

image

 

因此我们也可以写一个简单的枚举位操作辅助类型,如下:

static class EnumHelper

{

    //判读是否包含指定标志位

    public static bool HasFlag(long val, long flag)

    {

        return (val & flag) == flag;

    }

    //设置标志位

    public static long SetFlag(long val, long flag)

    {

        return val | flag;

    }

    //取消标志位

    public static long UnsetFlag(long val, long flag)

    {

        return val & ~flag;

    }

}

 

 

:D

抱歉!评论已关闭.