我想向左旋转1位字节。我正在查看此站点的几个示例,并遇到了此代码。虽然它有效,但我一步一步地欣赏 它是如何工作的。
unsigned int _rotl(const unsigned int value, int shift)
{
if ((shift &= sizeof(value)*8 - 1) == 0) //What does this do?
return value;
return (value << shift) | (value >> (sizeof(value)*8 - shift));
}
首先,第一部分的作用是什么?而且最后一部分不会那么多,你几乎要删掉一些比特?
例如:
说
value= 0x50 //01010000
shift = 4
我会 为了
value << shift
01010000 << 4 => 00000000
而且 值&gt;&gt; (sizeof(value)* 8 - shift)
01010000>> (4*8 - 4) => 00000000
因此,对两者进行OR运算都会给我0.我的理解显然是错误的,但是我很感激任何人,不管怎么说。这对于像我这样的乞丐来说。感谢。
答案 0 :(得分:2)
让我们一步一步地采取行动:
unsigned int _rotl(const unsigned int value, int shift)
{
if ((shift &= sizeof(value)*8 - 1) == 0) //What does this do?
return value;
return (value << shift) | (value >> (sizeof(value)*8 - shift));
}
第一行:
if ((shift &= sizeof(value)*8 - 1) == 0) //What does this do?
此声明是一个优化和检查汇总到一行。如果满足以下两个条件之一,则返回TRUE:
shift
指定的轮播次数无效该语句否则返回FALSE,但也计算实现所需结果所需的最小旋转次数,并将该值存储在shift
中。换句话说,它会计算shift = shift % size_of_integer_data_type
。
例如,如果您有一个32位整数,则将其旋转32位不会产生任何影响。如果将它旋转64,96或32的任何其他倍数,也不会完成任何操作。如果我们轮换的效果什么也没做,那么我们就会节省很多时间并且提前退出。
但是,我们可能还指定了比必要更多的工作。如果你有一个32位整数,那么将它旋转一位与旋转33位或65位或97位等效果相同。这段代码识别这个事实,所以如果你指定shift为97 ,它重新分配shift=1
并减少无关的轮换。
语句sizeof(value)*8 - 1
返回的值小于value
表示中的位数。例如,如果sizeof(value)
的计算结果为4(它将在具有32位整数的系统上计算),则为4*8 - 1 = 31
。
&=
运算符是按位AND,具有赋值。这意味着我们在shift
和sizeof(value)*8 - 1
之间执行按位AND,并将结果分配给shift
。和以前一样,该表达式的右侧等于value
中的位数减去1。因此,这具有掩蔽shift
的所有比特的效果,其大于value
的表示的大小,其反过来具有计算shift = shift % size_of_integer_data_type
的效果。
具体而言,重新考虑32位案例。和以前一样,sizeof(value)*8-1
的计算结果为31.按位,此值为0000 0000 0000 0000 0000 0000 0001 1111
。该值与shift
按位进行AND运算。 shift
的第6至第32位的任何位都设置为零,而第1至第5位的位不变。如果你要指定97个旋转,结果将是一个。
0000 0000 0000 0000 0000 0000 0110 0001 (97)
& 0000 0000 0000 0000 0000 0000 0001 1111 (31)
=========================================
0000 0000 0000 0000 0000 0000 0000 0001 (1)
这里要做的最后一件事是回忆一下,在C中,赋值语句的返回值是赋值的值。因此,如果shift
的新值为零,那么我们立即返回,否则我们继续。
第二行:
return (value << shift) | (value >> (sizeof(value)*8 - shift));
由于C没有旋转运算符(它只有左右移位),我们必须分别计算低阶位和高阶位,然后将它们与按位OR组合。这条线是分别计算每一面的简单问题。
语句value << shift
计算高位。它将位模式向左移动shift
个位置。另一个语句通过将位模式向右移位size_of_integer_type - shift
位来计算低位。这在示例中很容易看到。
假设value
的小数值为65535,而shift
的值为26.那么起始值为:
0000 0000 0000 0000 1111 1111 1111 1111 (65535)
左移给我们:
1111 1100 0000 0000 0000 0000 0000 0000 (65535 << 26)
正确的转变给了我们:
0000 0000 0000 0000 0000 0011 1111 1111 (65535 >> 6)
然后按位或组合这些结果:
1111 1100 0000 0000 0000 0000 0000 0000 (65535 << 26)
| 0000 0000 0000 0000 0000 0011 1111 1111 (65535 >> 6)
=========================================
1111 1100 0000 0000 0000 0011 1111 1111 (65535 rot 26)
您可以重新编写此代码并获得相同的正确结果:
unsigned int _rotl(const unsigned int value, int shift)
{
//Assume 8 bits in a byte
unsigned bits_in_integer_type = sizeof(value)*8;
shift = shift % bits_in_integer_type;
if( shift == 0 ) return value; //rotation does nothing
unsigned high_bits = value << shift;
unsigned low_bits = value >> (bits_in_integer_type - shift);
return high_bits | low_bits;
}
答案 1 :(得分:1)
unsigned int _rotl(const unsigned int value, int shift)
{
// If all bits in value are zero, do nothing and return
int bitmaskOfAllOnes = sizeof(value)*8 - 1;
if ((shift &= bitmaskOfAllOnes) == 0) //What does this do?
return value;
// Shift value to the left
(value << shift)
// shifting right to handle the wrap around
| (value >> (sizeof(value)*8 - shift));
}
e.g. using 16-bit ints
value = 0x1001
shift = 4
sizeof(value) => 2
//sizeof(value)*8 - 1 => 0xffff
sizeof(value)*8 - 1 => 15 Decimal
shift &= bitmaskOfAllOnes => 0x1001 (i.e. not zero)
value << shift => 0x0010
sizeof(value)*8 - shift => 12
value >> (sizeof(value)*8 - shift) => 0x001
0x0010 | 0x001 => 0x0011