【问题标题】:K&R C chapter 2 assignment operators and expressionsK&R C 第 2 章赋值运算符和表达式
【发布时间】:2021-06-04 15:35:51
【问题描述】:

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

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

函数 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 值(“负”和正值)的调试器运行代码。然后做同样的事情,但改用int x
  • 花几分钟查看bit shifting的真实值,看看效果。

标签: c bit-manipulation bitwise-operators assignment-operator twos-complement


【解决方案1】:

假设x 是二进制补码。为了说明,让我们使用 8 位宽度。 (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 标准没有说明它是算术还是逻辑。它将它留给实现来定义该实现使用哪个(或可能定义其他东西)。这可能是由于历史;早期的机器可能没有提供算术右移指令(甚至可能没有使用二进制补码),尽管现在似乎很难想象。

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

【讨论】:

    【解决方案2】:

    在二进制补码表示中,最高位保留用于符号。最高位为 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 执行按位与运算。位掩码的值为 1,它是 int 值的一个实例,除了最低位之外,所有位都为 0。如果最低位为 1,则 AND 运算将评估为 1(或在 C 中为真),如果最低位为 0,则评估为 0(或在 C 中为假)。如果 if 条件为,则增加一位的计数真的。

    【讨论】:

    • Re “如果你右移负数的位......”:C 2018 6.5.7 5 使负数的右移实现定义。
    • 它是实现定义的,因为 C 没有指定有符号数的硬件表示。一个补码不使用符号位,但同时具有 -0 和 +0 值。二进制补码是最常用的表示,使用符号位。
    • 当然,这可能是实现定义右移的原因。尽管如此,它是实现定义的,因此不能无条件地断言右移如此起作用。
    • @JimRogers,我想你可以说最高位也是一个符号位的补码?负值(包括-0)为1,正值(包括+0)为零。实际上,右移和复制符号位是否也适用于补码,直到四舍五入?取四位 -5,即1 010,右移得到1 101 或-2,右移得到1 110,或-1。实际上它看起来比二进制补码更好,因为它围绕零对称,所以((-b) >> 1) == -(b >> 1)。也就是说,我并没有停下来思考太久,所以如果我错了,请告诉我。
    • @JimRogers 我不是位运算专家,但我认为它只是巧合地适用于这些数字。 -6 是 1001,但 -3 是 1100。
    猜你喜欢
    • 1970-01-01
    • 2021-08-10
    • 1970-01-01
    • 2019-05-26
    • 1970-01-01
    • 2014-03-23
    • 2021-06-10
    • 2015-04-07
    • 1970-01-01
    相关资源
    最近更新 更多