繁体   English   中英

何时按位运算是合适的

[英]When are bitwise operations appropriate

我知道什么是按位操作的基本前提(虽然会欣赏“for dummies”的解释); 但是我不知道何时使用这种技术是合适的。

我的理解是, 较旧的CPU架构可以比其他操作更快地执行按位操作 ,因此知道如何使用它们是有利的。 鉴于此情况已不再适用; 是否仍然适合执行它们,如果是,它的目的和条件是什么? (我对C#语境特别感兴趣,但很高兴收到一般答案)

按位运算是快速检查可以在变量上设置的标志的好方法。

下面的示例强调了对Flag枚举使用按位运算以及将bitstuffed字段存储到数据库中的好处。 然后可以轻松检查bitstuffed字段以查看它是否包含Flag枚举中的单个值或值的子集。

例:

具有名为Permissiontinyint字段的User数据库表。 使用通过枚举创建的值填充该字段,其值为2 ^ n。

[Flags]
public enum Permission : byte
{
    None = 0,
    ManageUsers = 1 << 0,
    CreateOrders = 1 << 1,
    PurchaseEquipment = 1 << 2,
    CancelOrders = 1 << 3,
}

除了用于指定枚举中的值的按位运算(在编译时完成)之外,您还可以使用枚举来检查数据库中的Permission字段是否包含可能值的任何子集。 从数据库方面,您可以将值填充到单个字段中 - 无需为每个权限创建列,并且在代码方面,您可以轻松地检查值。

bitstuffing示例(Grant ManageUsers和CreateOrders):

Permission userPermissions = Permission.ManageUsers | Permission.CreateOrders;

权限检查示例:

public bool HasPermissions(Permission userPermissions, Permission permissionsToCheckFor)
{
    return permissionsToCheckFor == Permission.None ? 
        false : 
        (userPermissions & permissionsToCheckFor) == permissionsToCheckFor;
}

问题不在于按位运算比整数运算更快(尽管它们通常是这样),而是它们是用于不同目的的不同运算。

从概念上讲字节和短裤和int为位和位运算符的真正小数组布尔数组运算符。 在C#中,现在按位运算符主要用于[Flags]枚举和GetHashCode计算,但是有无数种方法可以使用位数组。

你是正确的,因为语言给你按位操作,你不应该只是因为你可以使用它们。 我看到人们在使用简单的布尔值时使用按位运算符,而这不是它们的用途。

在处理数据结构未与字节边界对齐的数据结构时,按位运算符非常有用。 通常,这是在带宽(或通用内存占用量)非常重要时完成的。 我致力于RTP视频流软件,并且按位操作用于读取/构建RTP传输分组以及用于读取视频编解码器流,其通常使用比特而不是字节来编码。

当空间非常宝贵时,它们在嵌入式控制情况下非常有用。 例如,单个字节的数据可以表示8个i / o位,并且掩码可以用于从i / o端口检索感兴趣的位(例如,如果PIN0 = 1, PIN1 = 2, PIN2 = 4, PIN3 = 8等等,然后:

  • 要获得PIN0的值,我们可以说PORT0 & PIN0 == 0
  • 要将PIN1设置为1,我们可以输入PORT0 |= PIN1
  • 要将PIN2设置为0,我们可以说PORT0 &= ~PIN2

远离嵌入式控制,我很少看到这些日子使用过。 在C#世界中,为每个感兴趣的值看到单独的布尔字段更为常见,因为开销对于现代硬件来说真的不是很大(尽管你可能遇到一个或两个案例,其中使用按位运算来保持许多这样的单个变量中的标志)。

图形中还有一个有趣的应用。 游标或边界框的一个巧妙技巧是通过将光标形状与下面的图像进行异或来添加它们。 再次执行相同的操作将产生原始图像。

我发现自己不时使用按位运算符的一种方法是使用二进制掩码生成给定字符串/数组的子集,它是这样的:(抱歉,c ++代码)

string s = "abcde";
for(int i = 0; i < 1<<s.size(); i++) {
  string tmp;
  for(int j = 0; j < s.size(); j++) if(i & 1<<j) tmp.push_back(s[j]);
  cout<<tmp<<endl; 
}

您可能想要查看这个富有洞察力的面向竞赛的编程教程: 有点乐趣:有趣的比特

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM