C++如何使用指针来循环移位数组元素
C++ how to use a pointer to circular shift array element
#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);
它只是延迟返回int
的指针,并对其执行所有位操作。它实际上与相同
unsigned int val = *q;
val = (val >> 8)|((val & 0xff) << 24);
*q = val;
程序本身具有未定义的行为。不能通过unsigned int*
指针访问char
数组。它还假设sizeof (unsigned int)
是4
,数组在元素之间没有填充,并且CPU具有特定的字节序。
这是怎么回事
指向数组的指针in
看起来像:
+---+---+---+---+
in --> | a | b | c | d |
+---+---+---+---+
假设每个字符都被编码为一个8位的序列(好吧,语言律师会认为一个字节不一定是8位,但在实践中,这种情况经常发生)。所以在二进制文件中,它看起来像:
+----------+----------+----------+----------+
in --> | 01100001 | 01100010 | 01100011 | 01100100 |
+----------+----------+----------+----------+
让我们假设int是由32位组成的。无符号int* q= (unsigned int*)in;
的丑陋的强制转换技巧是指示编译器处理指针,就好像它指向int
一样,将几个字符组合在一个值中:
+----------+----------+----------+----------+
q --> | 01100001 01100010 01100011 01100100 |
+----------+----------+----------+----------+
注意:为了简单起见,我在这里假设使用big-endian CPU架构。但我稍后会解释它是如何使用little-endian的
此示例中的二进制编码数字以十进制表示1633837924。
如果你现在执行(*q >> 8)
,它将把这个整数的位向右移动8位,在左边注入0位:
+----------+----------+----------+----------+
*q >>8 = | 00000000 01100001 01100010 01100011 |
+----------+----------+----------+----------+
'a' 'b' 'c'
现在0xff
在11111111
中是二进制的。如果您现在执行以下按位和操作(*q & 0xff)
,您将把除最后8位之外的所有位设置为0:
+----------+----------+----------+----------+
(*q&0xff) = | 00000000 00000000 00000000 01100100 |
+----------+----------+----------+----------+
'd'
如果将其与...<<24
组合,则通过向右注入0,将所有位向左移动24个位置:
+----------+----------+----------+----------+
(*q&0xff)<<24 = | 01100100 00000000 00000000 00000000 |
+----------+----------+----------+----------+
'd'
如果你现在将这两个术语与按位或组合,你将获得:
+----------+----------+----------+----------+
*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'
所以在这种情况下,它向右旋转。这是我所做的big-endian假设的结果。
但这安全吗
这个代码的问题在于,它假设了许多标准C++无法保证的东西。因此,它不能保证有效。它只在以下情况下工作:
char
是8比特长(因为右移和左移是8的倍数)- CCD_ 15是32比特长(因为它假定移位的组合恰好对应于32比特)
- 旋转的方向取决于字节序。只有小endian可以确保向左旋转
这里是对endianness的影响:
- 在我一步一步的解释中,我使用了big-endian,其中字节按正确的顺序依次形成整数。向右旋转
- 如果你有一个小端体系结构,这更有可能,字节将以相反的顺序作为整数加载到寄存器中(例如,内存顺序中的
a b c d
将作为d c b a
加载用于计算),然后字节将被向右移动和组合(例如,a d c b
),但当存储回内存时,字节将再次反转(例如b c d a
),因此如果查看单个字符,则对整数执行的向右旋转会导致向左旋转
- 使用for循环检查数组中的重复项
- 数组元素打印的递归方法
- 如何将字节数组元素替换为修改的十六进制 ASCII 符号?
- 为什么使用数组元素查找最大数字的程序不起作用?
- 在C++中使用 for 循环的数组迭代
- 数组元素更改值?
- 如何访问宏中定义的数组元素
- 循环中数组的行为
- 使用 C++ 从每个循环的数组中选择 n 个元素
- 试图为命名数组元素创建一个更好的循环
- C++如何使用指针来循环移位数组元素
- 使用 while / do-while 循环进行数组元素设置
- 使用 c while 循环遍历所有整数数组元素
- 循环以从根本上更改数组元素的 3x3 网格
- 为什么数组元素在循环内外具有不同的值
- 数组元素在for循环中产生不同的值
- 移位数组元素
- 基于范围的for循环错误地输出了具有cout的数组元素
- 循环遍历数组并找到最接近键的数组元素的最佳方法是什么
- c++将数组元素向左移位