写一个函数setbit(x,p,n,y),它返回x,从p位置开始的n位设置为y的最右边的n位,其他位保持不变
我搞不清我做错了什么。

#include <stdio.h>
unsigned setbits(unsigned int x, int p, int n, unsigned y);

int main()
{
    unsigned x = 213;
    unsigned y = 121;
    int p = 4;
    int n = 4;

    x = setbits(x, p, n, y);
    printf("%u\n", x);

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

从理论上讲,我得到了211,但是我的代码产生了210。K&R答案簿算法也返回210。我搞不清我在这里做错了什么。
编辑:这是答案本上的代码:
unsigned setbits(unsigned x, int p, int n, unsigned y)
{
    return x & ~(~(~0 << n) << (p + 1 - n)) | (y & ~(~0 << n)) << (p + 1 - n);
}

重新编辑。我在把代码分成几行的时候想出来了。问题是最后一个x旁边的括号放错了:
//original
{
    return ((~(~0 << n) & y) << (p + 1 - n) | (~(~(~0 << n)) << (p + 1 - n) & x));
}

//fixed
{
    return ((~(~0 << n) & y) << (p + 1 - n)) | (~(~(~0 << n) << (p + 1 - n)) & x);
}

这是被破解的密码。这看起来还不好吗?我是否应该使用这样的变量:
int setbits(unsigned x, int p, int n, unsigned y)
{
    unsigned z, k;

    z = y & ~(~0 << n);
    z = z << (p + 1 - n);
    k = ~((~(~0 << n)) << (p + 1 - n));
    k = k & x;

    return z | k;
}

最佳答案

措辞有点难理解,但我认为这正是它所要求的:

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

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

故障:
左半部分|
((1<<n)-1)将向左移动1n位,减去1将使所有位向右移动1。
<<(p-n)按p-n左移
~将它们反转,将这些位保留为0,其他位保留为1
x &将这些位转换为0。
右半部分|
x同上
((1<<n)-1)将仅屏蔽这些位
y &将把这些位p-n移到左边
<<(p-n)将或这些值放在一起,以便:
left | right位置开始的n位被设置为p的最右边的n位,保持y的其他位不变

10-04 18:23