我正在查看我目前在我的项目中的代码,并发现了这样的内容:
public enum MyEnum
{
open = 1 << 00,
close = 1 << 01,
Maybe = 1 << 02,
........
}
操作数是移位操作数,它将第<<
一个操作数左移第二个操作数中指定的位数。
但是为什么有人会在enum
声明中使用它呢?
这使您可以执行以下操作:
var myEnumValue = MyEnum.open | MyEnum.close;
无需计算 2 的倍数的位值。
(像这样):
public enum MyEnum
{
open = 1,
close = 2,
Maybe = 4,
........
}
这通常与位域一起使用,因为它很清楚模式是什么,消除了手动计算正确值的需要,从而减少了出错的机会
[Flags]
public enum SomeBitField
{
open = 1 << 0 //1
closed = 1 << 1 //2
maybe = 1 << 2 //4
other = 1 << 3 //8
...
}
避免Flags
手动输入枚举的值。
public enum MyEnum
{
open = 0x01,
close = 0x02,
Maybe = 0x04,
........
}
这里有很多答案描述了这个机制允许你做什么,但不是你为什么要使用它。这就是为什么。
精简版:
在与其他组件交互和与其他工程师交流时,这种表示法会有所帮助,因为它明确地告诉您正在设置或清除单词中的哪个位,而不是在数值中隐藏该信息。
所以我可以打电话给你说“嘿,打开文件是什么位?” 你会说,“位 0”。我会写在我的代码open = 1 << 0
中。因为右边的数字<<
告诉你位数。
.
长版:
传统上,单词中的位从右到左编号,从零开始。因此,最低有效位是第 0 位,当您朝着最高有效位前进时,您会向上计数。以这种方式标记位有几个好处。
一个好处是,无论字长如何,您都可以谈论相同的内容。例如,我可以说在 32 位字 0x384A 和 8 位字 0x63 中,都设置了位 6 和 1。如果你在另一个方向编号你的位,你不能这样做。
另一个好处是位的值只是 2 的位位置的幂。例如,二进制0101
设置了位 2 和 0。位 2 将值贡献4 (2^2)
给数字,位 0 贡献值 1 (2^0)。所以这个数字的值当然是 4 + 1 = 5。
冗长的背景解释让我们明白了这一点:<<
符号通过查看它就可以告诉您位数。
语句中的数字 1 本身1 << n
只是位位置 0 中设置的单个位。当您将该数字左移时,您会将该设置位移动到该数字中的不同位置。方便的是,您移动的数量会告诉您将要设置的位数。
1 << 5: This means bit 5. The value is 0x20.
1 << 12: This means bit 12. The value is 0x40000.
1 << 17: This means bit 17. The value is 0x1000000.
1 << 54: This means bit 54. The value is 0x40000000000000.
(You can probably see that this notation might be helpful if
you're defining bits in a 64-bit number)
当您与另一个组件交互时,这种表示法真的很方便,例如将一个字中的位映射到硬件寄存器。就像您可能有一个设备在您写入第 7 位时打开。因此硬件工程师会编写一份数据表,说明第 7 位启用该设备。你会写在你的代码ENABLE = 1 << 7
中。就这么简单。
哦拍。工程师刚刚向数据表发送了一个勘误表,说它应该是第 15 位,而不是第 7 位。没关系,只需将代码更改为
ENABLE = 1 << 15
.
如果ENABLE
实际上同时设置了第 7 位和第 1 位怎么办?
ENABLE = (1 << 7) | (1 << 1)
.
一开始它可能看起来很奇怪和迟钝,但你会习惯的。如果您明确需要知道某物的位数,您将不胜感激。
它只是为了成为一种更清洁/更直观的方式来编写这些位。1、2、3 是比 0x1、0x2、0x4 等更易于人类阅读的序列。
这是为了制作一个可以组合的枚举。
它的实际含义是:
public enum MyEnum
{
open = 1;
close = 2;
Maybe = 4;
//...
}
这只是创建[Flags]
枚举的一种更防弹的方法。
它等于二的幂。
public enum SomeEnum
{
Enum1 = 1 << 0, //1
Enum2 = 1 << 1, //2
Enum3 = 1 << 2, //4
Enum4 = 1 << 3 //8
}
使用这样的枚举,您将拥有如下所示的功能:
void foo(unsigned ind flags)
{
for (int = 0; i < MAX_NUMS; i++)
if (1 << i & flags)
{
//do some stuff...
//parameter to that stuff probably is i either enum value
}
}
并且调用该函数将是foo(Enum2 | Enum3);
,它将对所有给定的枚举值执行某些操作。