为什么标志枚举通常用十六进制值定义

我经常看到使用十六进制值的标志枚举声明。例如:

[Flags]
public enum MyEnum
{
None  = 0x0,
Flag1 = 0x1,
Flag2 = 0x2,
Flag3 = 0x4,
Flag4 = 0x8,
Flag5 = 0x10
}

当我声明一个 enum 时,我通常这样声明它:

[Flags]
public enum MyEnum
{
None  = 0,
Flag1 = 1,
Flag2 = 2,
Flag3 = 4,
Flag4 = 8,
Flag5 = 16
}

为什么有些人选择用十六进制而不是十进制表示值,有什么原因或理由吗?在我看来,当使用十六进制值时,意外地写 Flag5 = 0x16而不是 Flag5 = 0x10会更容易混淆。

42230 次浏览

这使得很容易看到这些是 二进制标志。

None  = 0x0,  // == 00000
Flag1 = 0x1,  // == 00001
Flag2 = 0x2,  // == 00010
Flag3 = 0x4,  // == 00100
Flag4 = 0x8,  // == 01000
Flag5 = 0x10  // == 10000

尽管 进展更加清楚地表明了这一点:

Flag6 = 0x20  // == 00100000
Flag7 = 0x40  // == 01000000
Flag8 = 0x80  // == 10000000

因为 [Flags]意味着枚举实际上是 < strong > bitfield 。对于 [Flags],您可以使用位 AND (&)和 OR (|)运算符来组合标志。在处理这样的二进制值时,使用十六进制值几乎总是更加明确。这正是我们最初使用 < strong > 十六进制 的原因。每个十六进制字符对应于 没错一个小写字母(4位)。对于十进制,这种1到4的映射不为真。

基本原理可能不同,但我看到的一个优点是,十六进制提醒你: “好吧,我们不再处理人类发明的以十为基数的任意世界中的数字。我们面对的是比特——机器的世界——我们将按照它的规则行事。”十六进制很少使用,除非您处理的是数据内存布局相对较低级的主题。用它来暗示我们现在的处境。

另外,我对 C # 不是很确定,但是我知道在 C x << y中是一个有效的编译时常量。 使用位移似乎最为明确:

[Flags]
public enum MyEnum
{
None  = 0,
Flag1 = 1 << 0,  //1
Flag2 = 1 << 1,  //2
Flag3 = 1 << 2,  //4
Flag4 = 1 << 3,  //8
Flag5 = 1 << 4   //16
}

因为有一个机械的,简单的方法可以把十六进制的二次幂加倍。在十进制中,这很难。这需要在你的头脑中进行长时间的乘法运算。在十六进制中,这是一个简单的改变。你可以一直执行到 1UL << 63,但是你不能用十进制。

因为对于人类来说,在旗帜上的位置更容易跟踪。每个十六进制数字可以容纳4位二进制数。

0x0 = 0000
0x1 = 0001
0x2 = 0010
0x3 = 0011


... and so on


0xF = 1111

通常,您希望您的标志不要重叠位,最简单的方法是使用十六进制值来声明您的标志。

因此,如果您需要16位的标志,您将使用4位的十六进制值,这样您就可以避免错误的值:

0x0001 //= 1 = 000000000000 0001
0x0002 //= 2 = 000000000000 0010
0x0004 //= 4 = 000000000000 0100
0x0008 //= 8 = 000000000000 1000
...
0x0010 //= 16 = 0000 0000 0001 0000
0x0020 //= 32 = 0000 0000 0010 0000
...
0x8000 //= 32768 = 1000 0000 0000 0000

我认为这是因为序列总是1,2,4,8,然后加上0。
如您所见: < br/>

0x1 = 1
0x2 = 2
0x4 = 4
0x8 = 8
0x10 = 16
0x20 = 32
0x40 = 64
0x80 = 128
0x100 = 256
0x200 = 512
0x400 = 1024
0x800 = 2048

依此类推,只要记住序列1-2-4-8,就可以构建所有后续标志,而不必记住2的幂

因为与十进制值相比,十六进制值与它所代表的二进制值更加一致:

0x001 = 0000 0000 0001 // 1
0x002 = 0000 0000 0010 // 2
0x004 = 0000 0000 0100 // 4
0x008 = 0000 0000 1000 // 8


0x010 = 0000 0001 0000 // 16
0x020 = 0000 0010 0000 // 32
0x040 = 0000 0100 0000 // 64
0x080 = 0000 1000 0000 // 128


0x100 = 0001 0000 0000 // 256
0x200 = 0010 0000 0000 // 512
0x400 = 0100 0000 0000 // 1024
0x800 = 1000 0000 0000 // 2048


// etc.