#include <iostream>
using namespace std;
void RotateLeft(unsigned char* in)
{
unsigned int* q= (unsigned int*)in;
*q = (*q >> 8)|((*q & 0xff) << 24);
}
int main() {
unsigned char temp[4] = {'a', 'b', 'c', 'd'};
RotateLeft(temp);
for (int i=0; i<4; i++) {
cout<<temp[i]<<endl;
}
}
输出为:b c d a。
你能解释一下这条线的工作原理:
*q = (*q >> 8)|((*q & 0xff) << 24);
答案 0 :(得分:3)
它只是引用指针,它返回一个int
,并对其执行所有位操作。它实际上与:
unsigned int val = *q;
val = (val >> 8)|((val & 0xff) << 24);
*q = val;
程序本身具有未定义的行为。您无法通过char
指针访问unsigned int*
数组。它还假设sizeof (unsigned int)
为4
,数组之间没有填充,以及CPU的特定字节序。
答案 1 :(得分:2)
数组的指针in
如下所示:
+---+---+---+---+
in --> | a | b | c | d |
+---+---+---+---+
让我们假设每个char都被编码为8位序列(好吧,语言律师会认为一个字节不一定是8位,但在实践中,情况经常如此)。所以在二进制文件中它看起来像:
+----------+----------+----------+----------+
in --> | 01100001 | 01100010 | 01100011 | 01100100 |
+----------+----------+----------+----------+
假设int由32位组成。使用unsigned int* q= (unsigned int*)in;
的丑陋casting技巧是指示编译器处理指针,就像指向int
一样,在单个值中组合多个char:
+----------+----------+----------+----------+
q --> | 01100001 01100010 01100011 01100100 |
+----------+----------+----------+----------+
注意:为简单起见,我假设这里有一个大端的CPU架构。但是我稍后会通过解释它如何与小端有效来回来 该示例中的二进制编码数字以十进制表示法表示1633837924。
如果您现在执行(*q >> 8)
,则此整数将shift the bits向右移动8位,在左侧注入0位:
+----------+----------+----------+----------+
*q >>8 = | 00000000 01100001 01100010 01100011 |
+----------+----------+----------+----------+
'a' 'b' 'c'
0xff
中的二进制文件中的11111111
。如果您现在执行以下bitwise and操作(*q & 0xff)
,则将所有位设置为0,除了最后8位:
+----------+----------+----------+----------+
(*q&0xff) = | 00000000 00000000 00000000 01100100 |
+----------+----------+----------+----------+
'd'
如果将其与...<<24
结合使用,则将所有位向左移动24个位置,方法是向右侧注入0:
+----------+----------+----------+----------+
(*q&0xff)<<24 = | 01100100 00000000 00000000 00000000 |
+----------+----------+----------+----------+
'd'
如果您现在将这两个术语与bitwise or结合使用,您将获得:
+----------+----------+----------+----------+
*q >>8 = | 00000000 01100001 01100010 01100011 |
+----------+----------+----------+----------+
'a' 'b' 'c'
+----------+----------+----------+----------+
(*q&0xff)<<24 = | 01100100 00000000 00000000 00000000 |
+----------+----------+----------+----------+
'd'
+----------+----------+----------+----------+
| (bitwise or) | 01100100 01100001 01100010 01100011 |
+----------+----------+----------+----------+
'd' 'a' 'b' 'c'
所以在这种情况下,它向右旋转。这是我所做的大端假设的结果。
这段代码的问题在于它假定了许多标准C ++无法保证的事情。所以它不能保证工作。它只适用于:
char
长8位(因为右移和左移是8的倍数)。int
长度为32位(因为它假设移位组合恰好对应32位)。此处对endianness的影响:
a b c d
将被加载为{{1}对于计算而言,然后将字节移位并组合,如右边所解释的那样(例如d c b a
),但是当存储回存储器时,字节将再次被反转(例如a d c b
),因此,如果查看各个字符,则对整数执行的向右旋转将导致向左旋转。