以下是一些与实际应用有关的位运算符:
- AND(&)
- XOR(^)
- NOT(~)
- OR(|)
- 左/右移位(<< / >>)
以下是一些与实际应用有关的位运算符:
大约三分钟前,我刚刚使用位异或(^
)计算了与PLC的串行通信的校验和...
在当今现代语言的抽象世界中,使用位运算的并不多。文件IO是一个容易想到的例子,但那只是在已经实现的东西上进行位运算操作,而不是实现使用位运算的东西。然而,作为一个简单的例子,以下c#代码演示如何去除文件的只读属性(以便可以使用新的FileStream并指定FileMode.Create):
//Hidden files posses some extra attibutes that make the FileStream throw an exception
//even with FileMode.Create (if exists -> overwrite) so delete it and don't worry about it!
if(File.Exists(targetName))
{
FileAttributes attributes = File.GetAttributes(targetName);
if ((attributes & FileAttributes.ReadOnly) == FileAttributes.ReadOnly)
File.SetAttributes(targetName, attributes & (~FileAttributes.ReadOnly));
File.Delete(targetName);
}
public enum MemoView :int
{
InboundMemos = 1, // 0000 0001
InboundMemosForMyOrders = 3, // 0000 0011
SentMemosAll = 16, // 0001 0000
SentMemosNotReceived = 48, // 0011
SentMemosReceivedNotRead = 80, // 0101
SentMemosRead = 144, // 1001
Outbox = 272, //0001 0001 0000
OutBoxErrors = 784 //0011 0001 0000
}
你看到这段代码的作用了吗?通过使用"与"(&)运算符与"Inbox"枚举值进行"与"运算,我知道"InboundMemosForMyOrders"在收件箱中。
下面是构建并返回定义当前选定文件夹视图的过滤器方法的简化版本:
private string GetFilterForView(MemoView view, DefaultableBoolean readOnly)
{
string filter = string.Empty;
if((view & MemoView.InboundMemos) == MemoView.InboundMemos)
{
filter = "<inbox filter conditions>";
if((view & MemoView.InboundMemosForMyOrders) == MemoView.InboundMemosForMyOrders)
{
filter += "<my memo filter conditions>";
}
}
else if((view & MemoView.SentMemosAll) == MemoView.SentMemosAll)
{
//all sent items have originating system = to local
filter = "<memos leaving current system>";
if((view & MemoView.Outbox) == MemoView.Outbox)
{
...
}
else
{
//sent sub folders
filter += "<all sent items>";
if((view & MemoView.SentMemosNotReceived) == MemoView.SentMemosNotReceived)
{
if((view & MemoView.SentMemosReceivedNotRead) == MemoView.SentMemosReceivedNotRead)
{
filter += "<not received and not read conditions>";
}
else
filter += "<received and not read conditions>";
}
}
}
return filter;
}
这是一个从字节格式的位图图像中读取颜色的示例
byte imagePixel = 0xCCDDEE; /* Image in RRGGBB format R=Red, G=Green, B=Blue */
//To only have red
byte redColour = imagePixel & 0xFF0000; /*Bitmasking with AND operator */
//Now, we only want red colour
redColour = (redColour >> 24) & 0xFF; /* This now returns a red colour between 0x00 and 0xFF.
I hope this tiny examples helps....
redColour
右移24位,怎么可能得到除了0以外的结果呢? - undefinedx<<3 + x
,而不是x*9
,这样可以节省几个周期。如果此代码在ISR中,则可以节省响应时间。tail = ((tail & MASK) + 1)
代替tail = ((tail +1) < size) ? tail+1 : 0
。按位与运算符用于掩码/提取字节的某个部分。
1字节变量
01110010
&00001111 Bitmask of 0x0F to find out the lower nibble
--------
00000010
位运算符对于长度为2的幂次方的数组循环非常有用。正如许多人所提到的,位运算符非常有用,并且在标志、图形、网络和加密中使用。不仅如此,它们还非常快速。我个人最喜欢的用途是在没有条件语句的情况下循环一个数组。假设您有一个以零为基础的数组(例如,第一个元素的索引为0),并且您需要无限循环它。无限循环是指从第一个元素到最后一个元素,然后返回到第一个元素。一种实现方法是:
int[] arr = new int[8];
int i = 0;
while (true) {
print(arr[i]);
i = i + 1;
if (i >= arr.length)
i = 0;
}
int[] arr = new int[8];
int i = 0;
while (true) {
print(arr[i]);
i = i + 1;
i = i % arr.length;
}
&
(按位与)运算符生成类似于0 .. length-1
的序列,像这样:i & length
。因此,了解这一点后,上面的代码变成了:int[] arr = new int[8];
int i = 0;
while (true){
print(arr[i]);
i = i + 1;
i = i & (arr.length - 1);
}
11
,7的二进制为111
,15的二进制为1111
等等,你懂的。现在,如果你将任何数字与一个二进制全为1的数字进行&
运算,会发生什么呢?假设我们这样做:num & 7;
num
小于或等于7,则结果将为num
,因为与1进行&
运算的每个位都是它本身。如果num
大于7,则在&
操作期间计算机会考虑7的前导零,这些前导零在&
操作后当然仍然保持为零,只有尾部部分将保留。如在二进制中9 & 7
的情况下,它看起来像:1001 & 0111
判断数字x
是否为2的幂?(在算法中很有用,例如计数器递增时,只需执行对数次操作)
(x & (x - 1)) == 0
x
的最高位是什么?(例如,这可以用于查找大于x
的最小2的幂)x |= (x >> 1);
x |= (x >> 2);
x |= (x >> 4);
x |= (x >> 8);
x |= (x >> 16);
return x - (x >>> 1); // ">>>" is unsigned right shift
如何找到整数 x
的最低位的 1
?(这有助于找到可以被2整除的次数。)
x & -x
x&-x
。 - PotatoswatterBase64编码是一个例子。Base64编码用于将二进制数据表示为可打印字符,以便通过电子邮件系统(和其他目的)发送。Base64编码将一系列8位字节转换为6位字符查找索引。位操作,移位,与运算,或运算,非运算非常有用,可以实现Base64编码和解码所需的位操作。
当然,这只是无数例子中的1个。