很多时候我看到使用十六进制值的标志枚举声明。例如:
[Flags]
public enum MyEnum
{
None = 0x0,
Flag1 = 0x1,
Flag2 = 0x2,
Flag3 = 0x4,
Flag4 = 0x8,
Flag5 = 0x10
}
当我宣布枚举时,我通常会这样声明:
[Flags]
public enum MyEnum
{
None = 0,
Flag1 = 1,
Flag2 = 2,
Flag3 = 4,
Flag4 = 8,
Flag5 = 16
}
为什么有些人选择用十六进制而不是十进制来写值?是否有理由或理由?我看到它的方式,使用十六进制值并且不小心写Flag5 = 0x16
而不是Flag5 = 0x10
时更容易混淆。
答案 0 :(得分:171)
理由可能会有所不同,但我看到的一个优点是十六进制提醒你:“好吧,我们不再处理任意人类发明的十世界世界中的数字。我们正在处理比特 - 机器的世界 - 我们将遵守其规则。“除非您处理数据内存布局很重要的相对较低级别的主题,否则很少使用十六进制。使用它暗示了我们现在所处的情况。
另外,我不确定C#,但我知道在C x << y
中是一个有效的编译时常量。
使用位移似乎最清楚:
[Flags]
public enum MyEnum
{
None = 0,
Flag1 = 1 << 0,
Flag2 = 1 << 1,
Flag3 = 1 << 2,
Flag4 = 1 << 3,
Flag5 = 1 << 4
}
答案 1 :(得分:40)
可以很容易地看到这些是二进制标志。
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
答案 2 :(得分:34)
我认为这只是因为序列总是1,2,4,8然后加上0
如你所见:
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的权力
答案 3 :(得分:13)
因为[Flags]
表示枚举实际上是bitfield。使用[Flags]
,您可以使用按位AND(&
)和OR(|
)运算符来组合标志。在处理这样的二进制值时,使用十六进制值几乎总是更清楚。这就是我们首先使用hexadecimal的原因。每个十六进制字符对应于完全一个半字节(四位)。对于十进制,这个1到4的映射不成立。
答案 4 :(得分:4)
因为有一种机械的,简单的方法可以将十六进制的功率加倍。在十进制中,这很难。它需要长时间的倍增。十六进制是一个简单的改变。你可以把它一直带到1UL << 63
,你不能做十进制。
答案 5 :(得分:2)
因为比特在旗帜中的人类更容易理解。每个十六进制数字都可以匹配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