这是怎么工作的?
指向数组的指针in 如下所示:
+---+---+---+---+
in --> | a | b | c | d |
+---+---+---+---+
假设每个 char 将被编码为 8 位序列(好吧,语言律师会争辩说一个字节不一定是 8 位,但在实践中,情况往往如此)。所以在二进制中它看起来像:
+----------+----------+----------+----------+
in --> | 01100001 | 01100010 | 01100011 | 01100100 |
+----------+----------+----------+----------+
假设 int 由 32 位组成。带有无符号int* q= (unsigned int*)in; 的丑陋casting 技巧是指示编译器处理指针,就好像它指向int,将多个字符组合在一个值中:
+----------+----------+----------+----------+
q --> | 01100001 01100010 01100011 01100100 |
+----------+----------+----------+----------+
注意:为了简单起见,我假设这里是一个大端 CPU 架构。但稍后我将通过解释它如何与 little endian 一起使用来回过头来解释它。
示例中的这个二进制编码数字以十进制表示 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 位)。
- 旋转方向取决于字节顺序。只有 little endian 才能确保向左旋转。
这里对endianness的影响:
- 在我的逐步解释中,我使用了 big-endian,其中字节按正确的顺序依次获取以形成整数。向右旋转。
- 如果您有一个更可能的小端架构,则字节将以相反的顺序作为整数加载到寄存器中(例如,内存顺序中的
a b c d 将加载为 d c b a 以进行计算) ,然后字节将按照右边的解释进行移位和组合(例如a d c b),但是当存储回内存时,字节将再次反转(例如b c d a),因此向右旋转完成如果查看单个字符,整数会导致向左旋转。