编写一个函数setbits(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;
}
3条答案
按热度按时间l5tcr1uw1#
措辞有点难以理解,但我认为这就是它所要求的:
细分:
((1<<n)-1)
将向左移动1 n位,减去1使所有向右的位都为1。<<(p-n)
左移p-n~
将其反转,使这些位为0,其他位均为1x &
和它到x
以将这些位变为0。((1<<n)-1)
同上y &
将仅屏蔽这些位<<(p-n)
将把这些位p-n向左移位left | right
将对这些值进行OR运算,从而:p
开始的n
位被设置为y
的最右边的n
位,而x
的其他位不变gk7wooem2#
qrjkbowd3#
书中解决方案
当
p=4
x
组件l1 = ~0 => 1111_1111_1111_1111_1111_1111_1111_1111
l2 = l1 << n => 1111_1111_1111_1111_1111_1111_1111_0000
l3 = ~(l2) => 0000_0000_0000_0000_0000_0000_0000_1111
l4 = (p + 1 - n) => 1
l5 = (l3) << (l4) => 0000_0000_0000_0000_0000_0000_0001_1110
l6 = ~l5 => 1111_1111_1111_1111_1111_1111_1110_0001
l7 = x & l6 => xxxx_xxxx_xxxx_xxxx_xxxx_xxxx_xxx0_000x
y
组件s1 = ~0 => 1111_1111_1111_1111_1111_1111_1111_1111
x1米11米1x
s3 = ~s2 => 0000_0000_0000_0000_0000_0000_0000_1111
s4 = (p + 1 - n) => 1
s5 = s3 << s4 => 0000_0000_0000_0000_0000_0000_0001_1110
s6 = y & s5 => 0000_0000_0000_0000_0000_0000_000y_yyy0
o = l7 | s6
输出
xxxx_xxxx_xxxx_xxxx_xxxx_xxxx_xxxy_yyyx
^all these uncounted bits!!!^ .
写一个函数setbits(x,p,n,y),它返回x,其中从位置p开始的n位被设置为y的 * 最右*n位,其他位不变。
我们是否从右边开始计数,然后一旦到达位置
p
,就开始向右计数n
位?unsigned
的类型为int
,可以使用$ gcc -o ansi-c_2-6 *.c -std=c89
$ ansi-c_2-6
结论
解决方案书是错误的。
溶液
附注
bits = CHAR_BIT * sizeof(
数据类型))
INT_MIN >> 31 == ~0
if p + n > 32
,你可以投上,但很快就会失控x
东东左侧
x1米30英寸1x
右侧
right_mask = INT_MAX >> (p - 1 + n)
x = x & (left_mask | right_mask)
y
东东中间
mid_mask = ~(left_mask | right_mask)
y = (y << (bits - p - n)) & mid_mask
return
东东x | y
TL;DR
书不对
做这个代替
限制条件:
n > 0