尽管每个人似乎都对标志用例着迷,但这并不是按位运算符的唯一应用(尽管可能是最常见的)。此外,C# 是一种足够高级的语言,其他技术可能很少使用,但仍然值得了解它们。这是我能想到的:
The <<
and >>
运算符可以快速乘以 2 的幂。当然,.NET JIT 优化器可能会为您执行此操作(以及其他语言的任何不错的编译器),但如果您真的为每一微秒而烦恼,您可能会写下这个是为了确定。
这些运算符的另一个常见用途是将两个 16 位整数填充到一个 32 位整数中。喜欢:
int Result = (shortIntA << 16 ) | shortIntB;
这对于与 Win32 函数直接连接很常见,有时出于遗留原因使用此技巧。
当然,当您想要迷惑没有经验的人时,例如在提供家庭作业问题的答案时,这些运算符非常有用。 :)
但在任何实际代码中,使用乘法会更好,因为它具有更好的可读性,并且 JIT 将其优化为shl
and shr
无论如何都有指令,所以不会有性能损失。
相当多奇怪的技巧处理^
运算符(异或)。这实际上是一个非常强大的运算符,因为具有以下属性:
A^B == B^A
A^B^A == B
- 如果你知道的话
A^B
那么就无法说出什么A
and B
是,但如果你知道其中之一,你就可以计算出另一个。
- 该运算符不会遇到任何溢出,例如乘法/除法/加法/减法。
我见过使用这个运算符的一些技巧:
在没有中间变量的情况下交换两个整数变量:
A = A^B // A is now XOR of A and B
B = A^B // B is now the original A
A = A^B // A is now the original B
双向链表,每一项只有一个额外变量。这在 C# 中用处不大,但对于每个字节都很重要的嵌入式系统的低级编程可能会派上用场。
这个想法是你跟踪第一个项目的指针;最后一项的指针;对于您跟踪的每一项pointer_to_previous ^ pointer_to_next
。这样,您可以从任意一端遍历列表,但开销仅为传统链表的一半。下面是遍历的C++代码:
ItemStruct *CurrentItem = FirstItem, *PreviousItem=NULL;
while ( CurrentItem != NULL )
{
// Work with CurrentItem->Data
ItemStruct *NextItem = CurrentItem->XorPointers ^ PreviousItem;
PreviousItem = CurrentItem;
CurrentItem = NextItem;
}
要从末尾遍历,您只需将第一行更改为FirstItem
to LastItem
。这是另一个节省内存的地方。
我使用的另一个地方^
在 C# 中定期使用运算符是当我必须为我的复合类型类型计算 HashCode 时。喜欢:
class Person
{
string FirstName;
string LastName;
int Age;
public int override GetHashCode()
{
return (FirstName == null ? 0 : FirstName.GetHashCode()) ^
(LastName == null ? 0 : LastName.GetHashCode()) ^
Age.GetHashCode();
}
}