K&R C 第 2 章赋值运算符和表达式

问题描述

赋值运算符不是我所期望的。到目前为止,本节中的所有内容都很熟悉,但他们解释它的方式使它看起来很陌生。我认为这是我对按位运算符感到困惑。

无论如何,这是我没有得到的部分。

函数 bitcount 计算其整数参数中 1 位的数量

/*bitcount: count 1 bits in x */
int bitcount (unsigned x)

{
  int b;

  for(b=0; x != 0; x >>= 1) {
    if(x & 01) 
      b++;
  return b;
}

将参数 x 声明为无符号可确保当它右移时,无论程序在何种机器上运行,空出的位都将填充零,而不是符号位。

并不是说我真的理解代码,但这最后一句话最让我困惑。这是什么意思? “符号位”是否表示“一”,这是否与二进制补码有关?

我真的很难完成按位运算。谁能推荐一些全面的材料来补充本书中的按位内容

解决方法

假设 x 是二进制补码。为了说明,让我们使用八位宽度。 (C 总是以更宽的宽度移动,至少是 int 的宽度。)

如果 x 是 64 (010000002) 并且我们将它右移一位,我们得到 32 (001000002)。当我们重复这个时,我们得到 16 (000100002),8 (000010002),4 (000001002),2 (000000102) 和 1 (000000012).

x 为 -64 时,二进制补码用 110000002 表示。如果我们将其右移并引入 0 位,则这些位为 011000002,表示 64+32 = 96。因此 -64 变为 96。现在,如果只是工作,那可能没问题与位。但是,如果我们想使用位移来划分数字,我们需要 -32,而不是 96。-32 的位是 111000002。所以我们可以通过引入 1 位而不是 0 位来获得它。 -16 的位是 111100002。那么-8、-4、-2和-1分别是111110002、111111002、111111102、111111112。在每种情况下,我们在移位时引入 1 位。

因此,如果我们想对除法使用位移位,有一个简单的位移位规则:将所有位右移一个位置,并将符号位保持原样(0 或 1)。如果我们要移位多于一位,请继续复制符号位。

这称为算术右移。因此,我们有两种右移:复制符号位的算术右移和引入 0 位的逻辑右移。

对于无符号类型,C 标准说右移是合乎逻辑的。

对于有符号类型,C 标准并没有说明它是算术还是逻辑。它留给实现来定义该实现使用哪个(或可能定义其他东西)。这可能是由于历史;早期的机器可能没有提供算术右移指令(甚至可能没有使用二进制补码),尽管现在似乎很难想象。

因此,当您编写向右移位的代码并希望确定将得到的结果时,您可以使用无符号类型来确保获得逻辑移位。

,

在二进制补码表示中,最高位是为符号保留的。正数的最高位为 0,负数为 1。 如果将负数的位右移,则最初位于最高位的 1 将被移至下一个低位,如果继续移动这些位,最终会以最低位结束。 在代码中,for 循环将 x 的位移位一位,并将移位后的值赋给 x。

for (b = 0; x != 0; x >>=1 )

第一个b,用来统计数字中1位的个数设置为0。

继续循环的条件是 x != 0。当所有 1 位都移出 x 时,唯一剩下的将是 0 位。 x 将等于 0。

每次迭代后执行的操作是将 x 中的值右移 1。

循环体中的 if 条件对 x 执行按位 AND 运算。位掩码的值为 1,它是 int 值的实例,除最低位之外的所有位均为 0。如果最低位为 1,则 AND 运算将评估为 1(或在 C 中为真),如果最低位为 0,则为 0(或在 C 中为假)。如果 if 条件为,则一位的计数增加真的。