以下是一些与实际应用有关的位运算符:
- AND(&)
- XOR(^)
- NOT(~)
- OR(|)
- 左/右移位(<< / >>)
以下是一些与实际应用有关的位运算符:
位域(标志)
它们是表示由几个“是或否”属性定义状态的最有效方式。ACL是一个很好的例子;如果您有4个离散的权限(读取,写入,执行,更改策略),最好将其存储在1个字节中,而不是浪费4个字节。这些可以映射到许多语言中的枚举类型以获得更多方便。
端口/套接字通信
总是涉及校验和、奇偶校验位、停止位、流控算法等,在这种情况下通常依赖于单个字节的逻辑值而不是数值,因为介质可能只能一次传输一位。
压缩、加密
这两个都严重依赖于按位算法。以deflate算法为例-所有内容都是按位处理的,而不是按字节处理。
有限状态机
我主要讲的是一些嵌入式硬件中的有限状态机,虽然它们也可以在软件中找到。这些是组合性的——它们可能实际上被编译成一堆逻辑门,因此它们必须表示为AND
、OR
、NOT
等。
图形
这里几乎没有足够的空间来涉及这些运算符在图形编程中使用的每个领域。XOR
(或^
)在这里特别有趣,因为第二次应用相同的输入将撤消第一次。旧的GUI曾经依靠此进行选择突出显示和其他叠加,以消除昂贵的重新绘制的需要。它们在慢速图形协议(即远程桌面)中仍然有用。
这只是我想到的前几个例子 - 这远远不是一个详尽的列表。
它是奇数吗?
(value & 0x1) > 0
它是否可以被二整除(偶数)?
(value & 0x1) == 0
我在一个CMS的安全模块中使用了位操作。该系统有许多页面,只有当用户在相应的用户组中时才能访问这些页面。一个用户可以属于多个用户组,因此我们需要检查用户组和页面组之间是否存在交集。为此,我们为每个用户组分配了唯一的2的幂次方标识符,例如:
Group A = 1 --> 00000001
Group B = 2 --> 00000010
Group C = 3 --> 00000100
我们将这些值进行逻辑或操作,并将该值(作为单个整数)与页面一起存储。例如,如果页面可以由A组和B组访问,则将值3(在二进制中为00000011)存储为页面访问控制。同样地,我们将OR后的组标识符的值与用户一起存储,以表示他们所在的组。
因此,要检查给定用户是否可以访问给定页面,只需将这些值进行逻辑与操作,并检查该值是否非零。这非常快速,因为此检查在单个指令中实现,没有循环,也没有数据库交互。
下面是一些常见的处理存储为单个比特的标志的习惯用语。
enum CDRIndicators {
Local = 1 << 0,
External = 1 << 1,
CallerIDMissing = 1 << 2,
Chargeable = 1 << 3
};
unsigned int flags = 0;
设置可计费标志:
flags |= Chargeable;
清除 CallerIDMissing 标志:
flags &= ~CallerIDMissing;
测试是否设置了CallerIDMissing和Chargeable:
if((flags & (CallerIDMissing | Chargeable )) == (CallerIDMissing | Chargeable)) {
}
volatile uint32_t *register = (volatile uint32_t *)0x87000000;
uint32_t value;
uint32_t set_bit = 0x00010000;
uint32_t clear_bit = 0x00001000;
value = *register; // get current value from the register
value = value & ~clear_bit; // clear a bit
value = value | set_bit; // set a bit
*register = value; // write it back to the register
htonl()
和htons()
使用&
和|
运算符实现(对于字节序与网络序不匹配的机器):#define htons(a) ((((a) & 0xff00) >> 8) | \
(((a) & 0x00ff) << 8))
#define htonl(a) ((((a) & 0xff000000) >> 24) | \
(((a) & 0x00ff0000) >> 8) | \
(((a) & 0x0000ff00) << 8) | \
(((a) & 0x000000ff) << 24))
htons()
和 htonl()
是 POSIX 函数,用于将主机(h
)字节序转换为网络(n
)字节序,以实现对一个 short
或 long
进行端序交换。 - Carl Norumhtonl()
不是用于 32 位 int
值吗?在许多语言中,long
表示 64 位。 - Aaron Franke我使用它们从打包的颜色值中获取RGB(A)的值,例如。
(a & b) >> c
提取一个整数表示的 ARGB 值中的单个颜色值比 a % d / e
快了超过5倍。针对10亿次迭代分别耗时6.7秒和35.2秒。 - Benji XVIuint
而不是int
),那么这两个示例应该具有相同的速度。 - Aaron Franke当我有一堆布尔标志时,我喜欢将它们全部存储在一个整数中。
我使用按位与(bitwise-AND)来获取它们。例如:
int flags;
if (flags & 0x10) {
// Turn this feature on.
}
if (flags & 0x08) {
// Turn a second feature on.
}
等等。
if (flags.feature_one_is_one) { // turn on feature }
。它在ANSI C标准中,因此可移植性不应该是一个问题。 - polandeer& = AND:
屏蔽特定位。
您正在定义应该显示或不显示的特定位。 0x0 & x将清除字节中的所有位,而0xFF不会更改x。 0x0F将显示较低半字节中的位。
Conversion:
为了将较短的变量转换为具有位标识的较长变量,需要调整位,因为int中的-1是0xFFFFFFFF,而long中的-1是0xFFFFFFFFFFFFFFFF。为了保留标识,转换后应用掩码。
|=OR
设置位。 如果它们已经设置,则位将独立设置。 许多数据结构(位字段)具有像IS_HSET = 0,IS_VSET = 1这样的标志,可以独立设置。 要设置标志,请应用IS_HSET | IS_VSET(在C和汇编中非常方便)
^=XOR
查找相同或不同的位。
~= NOT
翻转位。
可以证明,所有可能的本地位操作都可以通过这些操作来实现。 因此,如果您愿意,可以仅通过位操作来实现ADD指令。
一些奇妙的技巧:
http://www.ugcs.caltech.edu/~wnoise/base2.html
http://www.jjj.de/bitwizardry/bitwizardrypage.html
= ~
,而不是|=
,后者是OR。 - Mike DeSimone& = AND
- 为什么我要清除所有位,为什么我想要获取未修改的字节版本,以及对低四位应该做什么? - confused00xor
运算。我可以想到很多理由为什么你想要提取低四位。特别是如果这个低四位是数据结构的一部分,并且你想将其用作掩码或者与另一个结构体进行OR
运算。 - James M. Lay加密是由位运算组成的。
你可以将它们用作快速而简单的数据哈希方式。
int a = 1230123;
int b = 1234555;
int c = 5865683;
int hash = a ^ b ^ c;