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

Adi*_*ter 117 .net c# enums enum-flags

很多时候,我看到使用十六进制值的标志枚举声明.例如:

[Flags]
public enum MyEnum
{
    None  = 0x0,
    Flag1 = 0x1,
    Flag2 = 0x2,
    Flag3 = 0x4,
    Flag4 = 0x8,
    Flag5 = 0x10
}
Run Code Online (Sandbox Code Playgroud)

当我声明一个枚举时,我通常会这样声明:

[Flags]
public enum MyEnum
{
    None  = 0,
    Flag1 = 1,
    Flag2 = 2,
    Flag3 = 4,
    Flag4 = 8,
    Flag5 = 16
}
Run Code Online (Sandbox Code Playgroud)

是否有理由或理由为什么有些人选择用十六进制而不是十进制来写值?我看到它的方式,使用十六进制值并意外写Flag5 = 0x16而不是更容易混淆Flag5 = 0x10.

exi*_*all 179

基本原理可能有所不同,但我看到的一个优点是,十六进制提醒你:"好吧,我们不再处理任意人类发明的十世界世界中的数字.我们正在处理比特 - 机器的世界 - 而我们"按照规则行事吧." 除非您处理数据内存布局很重要的相对较低级别的主题,否则很少使用十六进制.使用它暗示了我们现在所处的情况.

另外,我不确定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
}
Run Code Online (Sandbox Code Playgroud)

  • 另一个有趣的事实是`x << y`符号.`1 << 10 = KB`,`1 << 20 = MB`,`1 << 30 = GB`等.如果你想为一个缓冲区创建一个16 KB的数组,你可以去`var buffer = new byte [16 << 10];这真的很好. (35认同)
  • 使用此表示法+1时,您永远不会在枚举值计算中出错 (13认同)
  • 这非常有趣,它实际上也是一个有效的C#枚举. (7认同)
  • @Eric:嗯,我不知道为什么,但我总是确定它确实分配了 2 的幂值。我刚刚查了一下,我想我错了。 (2认同)

Ode*_*ded 42

这使得很容易看出这些是二进制标志.

None  = 0x0,  // == 00000
Flag1 = 0x1,  // == 00001
Flag2 = 0x2,  // == 00010
Flag3 = 0x4,  // == 00100
Flag4 = 0x8,  // == 01000
Flag5 = 0x10  // == 10000
Run Code Online (Sandbox Code Playgroud)

虽然进展使它更清晰:

Flag6 = 0x20  // == 00100000
Flag7 = 0x40  // == 01000000
Flag8 = 0x80  // == 10000000
Run Code Online (Sandbox Code Playgroud)

  • @Light - 完全没有.这很常见,所以你可以看到它们是如何对齐的.只是使位更明确:) (4认同)
  • 我实际上在0x1,0x2,0x4,0x8前面添加了一个0 ...所以我得到0x01,0x02,0x04,0x08和0x10 ...我发现更容易阅读.我搞砸了什么? (3认同)
  • 如果你不使用十六进制,@ LightStriker就会把它抛出那里*确实*很重要.仅以零开头的值被解释为八进制.所以`012`实际上是'10`. (2认同)

小智 35

我认为这只是因为序列总是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
Run Code Online (Sandbox Code Playgroud)

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


Jon*_*art 13

因为[Flags]意味着枚举真的是一个位域.有了[Flags]你可以使用按位AND( &)和OR( |)运营商的标志结合使用.在处理这样的二进制值时,使用十六进制值几乎总是更清楚.这就是我们首先使用十六进制的原因.每个十六进制字符恰好对应一个半字节(四位).对于十进制,这个1到4的映射不成立.

  • 实际上,使用按位运算的能力与 flags 属性无关。 (2认同)

usr*_*usr 5

因为有一种机械的、简单的方法可以将十六进制的 2 的幂加倍。在十进制中,这很难。它需要在你的头脑中进行长时间的乘法运算。在十六进制中,这是一个简单的更改。您可以一直执行此1UL << 63操作,而在十进制中无法执行此操作。


Onl*_*You 5

因为人类更容易理解标志中的位。每个十六进制数字可以容纳 4 位二进制数。

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

... and so on

0xF = 1111
Run Code Online (Sandbox Code Playgroud)

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

因此,如果您需要 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
Run Code Online (Sandbox Code Playgroud)