理解按位与运算符

51

我一直在阅读《Objective-C程序设计》(Kochan著)中有关位运算符的部分。

虽然迄今为止,我已经非常理解书中介绍的大部分内容,但是这一部分让我非常困惑。

以下是书中的一句引用:

按位与运算符

按位与运算通常用于掩码操作。也就是说,此运算符可以轻松地将数据项的特定位设置为0。例如,下面的语句:

w3 = w1 & 3;

将w1与常量3按位与,并将结果赋值给w3。这样做的效果是将w中除了最右边两位以外的所有位都设为0,同时保留w1中最右边的两位。

与C语言中的所有二进制算术运算符一样,通过添加等号,二进制位运算符也可以用作赋值运算符。该语句为:

word &= 15;
因此具有与以下代码执行相同的功能:
word = word & 15;
此外,它的效果是将 word 的除最右边四个位以外的所有位置为 0。在执行按位运算时,如果使用常量,通常更方便的做法是以八进制或十六进制表示常量。
好的,这就是我试图理解的内容。现在,我对整个概念都感到非常困惑,我只是想寻求一些澄清,如果有人愿意帮助我的话。
当书中提到“设置所有位”时,现在是所有位。什么是位?它不只是二进制中的 0 或 1 吗?
如果是这样,为什么在第一个示例中,除了“最右边的 2 位”之外的所有位都是 0?是否因为它是从我们的常量中减去 3-1,所以是 2?
谢谢!

相关:按位操作和用法,适用于一般的按位布尔运算,指出它们可以同时进行32(或64或其他)个单独的按位布尔运算。 - Peter Cordes
4个回答

154

数字可以用二进制表示,如下所示:

3    = 000011
5    = 000101
10   = 001010

我将会假设您熟悉二进制。

按位与是指将两个数字排列在一起,并创建一个新数字,其中两个数字都为1的位置上有一个1(其他位置为0)。

例如:

    3          =>  00011
  & 5          =>  00101
------           -------
    1              00001

按位或是指将两个数字排列在一起,并创建一个新的数字,其中任何一个数字为1的地方都会有1(其他所有位置都是0)。

例如:

    3          =>  00011
  | 5          =>  00101
------           -------
    7              00111

按位异或(exclusive OR)是指将两个数字排列在一起,创建一个新的数字,在其中一个数字为1且另一个数字为0的位置上放置1(其他位置上都为0)。

例如:

    3          =>  00011
  ^ 5          =>  00101
------           -------
    6              00110  

按位非(Not OR)指的是对两个数进行按位或操作,然后将所有结果反转(原来为0的变成1,原来为1的变成0)。
按位非与(Not AND)指的是对两个数进行按位与操作,然后将所有结果反转(原来为0的变成1,原来为1的变成0)。
继续说,为什么word &= 15会将除了最右边的4个比特位之外的所有位置为0?现在你应该能够理解了...
     n          =>  abcdefghjikl
  & 15          =>  000000001111
------            --------------
     ?              00000000jikl

(0 AND a = 0, 0 AND b = 0, ... j AND 1 = j, i AND 1 = i, ...)

这个语句有什么用处呢?在许多编程语言中,我们使用所谓的“位掩码”。位掩码本质上是一个代表许多小数合并在一起的数字。我们可以使用OR将数字组合在一起,并使用AND将它们分开。例如:
int MagicMap = 1;
int MagicWand = 2;
int MagicHat = 4;

如果我只有地图和帽子,我可以表达为myInventoryBitmask = (MagicMap | MagicHat),结果是我的比特掩码。如果我什么也没有,那么我的比特掩码就是0。如果我想要查看我是否有魔杖,我可以执行以下操作:

int hasWand = (myInventoryBitmask & MagicWand);
if (hasWand > 0) {
  printf("I have a wand\n");
} else {
  printf("I don't have a wand\n");
}

你明白吗?

编辑:更多内容

你还会遇到“位移”运算符:<< 和 >>。这只是意味着“将所有东西向左移动n位”或“将所有东西向右移动n位”。

换句话说:

1 << 3 = 0001 << 3 = 0001000 = 8

和:

8 >> 2 = 01000 >> 2 = 010 = 2


2
哇!非常感谢您的回复。根据这个在线计算器: http://www.convertit.com/go/convertit/calculators/math/base_converter.asp3 = 11 5 = 101 10 = 1010您是不是在二进制数字前面加了什么前缀? - Qcom
2
@BOSS 是的,我在前面加上0来使它们对齐,并确保它们不是负数“2的补码”数字。 - Dave DeLong
1
@BOSS 它们非常有用。它的工作原理是,您基本上将位掩码的每个“列”视为表示一个项目(在此示例中为您的库存)的“开/关开关”。 您定义项目使其(二进制)仅具有单个1,其余全部为0。 这意味着您可以将它们OR在一起而不会丢失任何信息。 它真的很有用,在Cocoa中您会经常看到它们(大多数具有“options:”参数的方法都要求使用选项的位掩码)。 - Dave DeLong
只是想知道,显然这些位掩码也可以用于精灵(http://en.wikipedia.org/wiki/Mask_(computing)#Image_masks)。一旦我在理解我的objc-c方面更进一步,是否有可能使用这种方法开发一个横向滚动的游戏? - Qcom
很棒的评论,现在我明白了什么是位运算 AND OR XOR,非常有趣,谢谢!! - CuteMeowMeow
显示剩余7条评论

2
"Bit"是二进制数字的缩写。是的,它只能是0或1。一个字节通常包含8个二进制数字,并且它们的书写方式类似于十进制数——最高有效位在左边,最低有效位在右边。
在你的例子中,w1 & 3屏蔽了除了最后两位(最右边)以外的所有内容,因为3在二进制下是00000011。(2 + 1)AND操作如果被AND的任意位为0,则返回0,因此除了最后两位,其余都自动变成了0。

1
w1 =    ????...??ab
3  =    0000...0011
--------------------
&  =    0000...00ab

0 & 任何位 N = 0

1 & 任何位 N = N

因此,任何与3进行按位与运算的值都会将除最后两位外的所有位设置为0。在这种情况下,最后两位a和b将被保留。


1

@cHao & 大家好:

不! 位并不是数字。它们不是0或1!

嗯,0和1是可能的且有效的解释。零和一是典型的解释。

但是一位只是一个东西, 表示简单的二选一。它表示“是”或“不是”。它没有说出关于这个东西“它”本身的任何事情。它不会告诉你它是什么。

在大多数情况下,这不会让你烦恼。你可以像通常那样将它们视为数字(或数字的部分、数字),你(或者编程语言、CPU 和其他硬件的组合,你知道作为“典型”)通常这样做 - 也许你永远不会与它们产生麻烦。

但是,如果你交换了“0”和“1”的含义,也没有什么原则性的问题。好吧,如果你在汇编编程时这样做,你会发现有些助记符会执行其他逻辑,而不是使用它们的名称所告诉你的逻辑,数字会被取反等等。

如果你想的话,看看这个http://webdocs.cs.ualberta.ca/~amaral/courses/329/webslides/Topic2-DeMorganLaws/sld017.htm

问候


2
喜欢这个回答的摇摆不定。位不是零或一!...除非它们由0和1表示,这是典型的表示方式。但是,如果您交换“0”和“1”的含义,则没有问题...除非您在汇编语言中编程,否则会有问题。这种观点介于无用的学究式和疯狂之间。 - cHao
1
听起来像是纯粹主义的受害者。 - NYC Tech Engineer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接