C中位的正确旋转
我正在 K&R 中进行练习 2-8,它要求我们编写函数rightrot(int x, int n),使得 的所有位x都向右移动 n 次,而从右端掉下来的位重新出现在左端。
这是我尝试的解决方案,我将每一位一位一位地移动:
int rightrot(int x, int n)
{
int i, rmb;
for(i = 0; i < n; ++i)
{
// get right-most bit
rmb = x & 1;
// shift 1 to right
x = x >> 1;
// if right-most bit is set, set left-most bit
if (rmb == 1)
x = x | (~0 ^ (~0 >> 1) );
}
return x;
}
当我执行时rightrot(122, 2),我希望得到94因为122is1111010和94is 1011110。相反,我知道30哪个恰好是0011110. 显然,我设置最左边位的方法并没有像我期望的那样工作。有没有人发现明显的错误?我只是在学习捕获位等。
注意:我从这篇文章中获得了设置最左边位的技术。
回答
我们来分析一下(~0 ^ (~0 >> 1) ):
~0is 又-1
~0 >> 1是-1,如果符号位是1右移将用1s填充新位。
-1 ^ -1是0。
x = x | 0是x。
解决方案是,如果您想进行位操作,您应该使用无符号数据类型。
所以你应该使用行x = x | (~0u ^ (~0u >> 1) );
来避免其他问题,参数x也应该是unsigned int.
https://ideone.com/7zPTQk
- *`~0 >> 1` is again `-1`,* Note that is [implementation-defined](https://port70.net/~nsz/c/c11/n1570.html#6.5.7p5).