k& r与位操作混淆

时间:2010-01-16 03:24:53

标签: c bit-manipulation kr-c

练习是: 写一个函数setbits(x,p,n,y)返回x,其中n位从位置p开始,设置为y的最右边n位,其他位保持不变。

我尝试解决方案是:

#include <stdio.h>

unsigned setbits(unsigned, int, int, unsigned);

int main(void)
{
    printf("%u\n", setbits(256, 4, 2, 255));
    return 0;
}

unsigned setbits(unsigned x, int p, int n, unsigned y)
{
    return (x >> (p + 1 - n)) | (1 << (n & y));
}

这可能不正确,但我在正确的道路上吗?如果没有,我做错了什么?我不确定为什么我不完全理解这一点,但我花了大约一个小时试图想出这个。

感谢。

3 个答案:

答案 0 :(得分:5)

这是你的算法:

  1. 如果n为0,则返回x。
  2. 取1,然后左移n次,然后减去1.请拨打mask
  3. 左移掩码p次调用此mask2
  4. And x与mask2的反转。 And y带面具,左移p次。
  5. Or这两个操作的结果,并返回该值。

答案 1 :(得分:2)

我认为答案是对2.9节中的getbits示例稍加修改的应用程序。

让我们按如下方式分解:

Let bitstring x be 1 0 1 1 0 0
Let bitstring y be 1 0 1 1 1 1

positions -------->5 4 3 2 1 0

设置p = 4 and n =3为我们提供了来自x的位串0 1 1。它从4开始,到2结束,跨越3个元素。

我们想要做的是将0 1 1替换为1 1 1(位串y的最后三个元素)。

让我们暂时忘记左移/右移并按如下方式显示问题:

我们需要从位串y中获取最后三位数,即1 1 1

1 1 1直接放在bitstring x的4 3 and 2位置下。

0 1 1替换为1 1 1,同时保持其余位完整...

现在让我们进一步了解一下......

我的第一个陈述是:

We need to grab the last three digits from bitstring y which is 1 1 1

从位串中隔离位的方法是首先从具有全0的位串开始。 我们最终得到0 0 0 0 0 0

0s有这个令人难以置信的属性,其中按位'和'使用另一个数字给我们所有的0和按位'|'用另一个数字给我们回到那个其他数字。

0本身在这里没有用......但它告诉我们如果我们'|' y的最后三位数字为'0',我们最终会得到1 1 1. y中的其他位在这里并不关心我们,因此我们需要找出一种方法来将这些数字归零,同时保持最后三位完整。实质上我们需要数字0 0 0 1 1 1

让我们看一下所需的一系列转换:

Start with  ->  0 0 0 0 0 0
apply ~0    ->  1 1 1 1 1 1
lshift by 3 ->  1 1 1 0 0 0 
apply ~     ->  0 0 0 1 1 1
& with y    ->  0 0 0 1 1 1 & 1 0 1 1 1 1 -> 0 0 0 1 1 1

这样我们就可以将最后三位用于设置......

我的第二个陈述是:

  

将1 1 1直接置于位串x 4的位置4 3和2之下。

可以在第2.9节的getbits示例中找到执行此操作的提示。我们对位置4,3和2的了解可以从值p = 4 and n =3中找到。 p是位置,n是bitset的长度。结果p+1-n给出了最右边位的位集偏移量。在此特定示例中p+1-n = 4 +1-3 = 2

所以..如果我们在字符串0 0 0 1 1 1上左移2,我们最终得到0 1 1 1 0 0。如果您将此字符串放在x下,您会注意到1 1 1与x的位置4 3 and 2对齐。

我想我终于到了某个地方......我做的最后一句话是......

  

将0 1 1替换为1 1 1,同时保持其余位完整...

让我们现在回顾一下我们的字符串:

x           ->   1 0 1 1 0 0
isolated y  ->   0 1 1 1 0 0

按位或按这两个值给出了我们在这种情况下所需的内容:

1 1 1 1 0 0 

但是如果不是1 1 1而是1 0 1,我们就会x -> bit by bit...1(stays) 0(changes) 1(changes) 1(changes) 0(stays) 0(stays) 失败,所以如果我们需要多挖一点来获得我们的“银弹”......

让我们再看一下上面两个字符串......

1 x x x 0 0

理想情况下......我们需要位串Bitwise complement of isolated y -> 1 0 0 0 1 1 & this with x gives us -> 1 0 0 0 0 0 | this with isolated y -> 1 1 1 1 0 0 (TADA!) ,其中x将与1交换。 这是一个有助于我们的直觉的飞跃......

{{1}}

希望这篇长篇文章能帮助人们理解并解决这些比特掩码问题...

谢谢

答案 2 :(得分:0)

请注意,~0 << i会为您提供一个数字,其最低有效i位设置为0,其余位设置为1。同样,~(~0 << i)会为您提供一个数字,其中最不重要的i位设置为1,其余位设置为0

现在,要解决您的问题:

  1. 首先,您需要一个数字,其除n位以外的所有位(位于p的位置设置为x的位。为此,除了从位置1开始的n位之外,您需要一个除p之外的掩码:
    1. 此掩码设置了最高(最重要)位,从位置p+1的位开始。
    2. 此掩码也设置了最不重要的p+1-n位。
  2. 获得上述面具后,&此面具的x会在步骤1中为您提供所需的数字。
  3. 现在,您需要一个设置nyp+1-n的数字,向左移位n位。
    1. 您可以轻松制作仅设置了最低&位的掩码,并y将其设置为y以提取n最不重要的{{1}比特。
    2. 然后,您可以将此数字移动p+1-n位。
  4. 最后,您可以按位或(|)步骤2和3.2的结果来获取您的号码。
  5. 清除泥土? : - )

    (上述方法应该与数字的大小无关,我认为这很重要。)

    编辑:查看您的工作:n & yn位没有任何作用。例如,如果n为8,则需要y的最后8位,但n & y将选择y的第4位(二进制中的8为1000) 。所以你知道这不可能是正确的。类似地,右移x p+1-n次为您提供一个数字,其中最重要的p+1-n位设置为零,其余位由{{的最高位组成。 1}}。这不是你想要的。

相关问题