我正在寻找一种方法来反转字符数组中的字节。我还需要在将它们放在正确位置之前反转被交换字节的各个位。 例如说我有一个char arr [1000],其arr [0] = 00100011和arr [999] = 11010110,我想交换arr [0]和arr [999]并另外反转每个中的位。因此输出将是arr [999] = 11000100(arr [0]的反转位)和arr [0] = 01101011(arr [999]的反转位)。
我有一些代码在一个字节内进行位反转:
static char reverseByte(char val)
{
char result = 0;
int counter = 8;
while (counter-- < 0)
{
result <<= 1;
result |= (char)(val & 1);
val = (char)(val >> 1);
}
return result;
}
但是这意味着运行一个外部循环来进行字节交换,然后在上面的情况下为每个字节运行上面的小循环,即1000。这是正确的方法吗?有没有更好的方法来实现这一目标? 任何帮助将不胜感激。
答案 0 :(得分:1)
这个怎么样?:
#include <stdio.h>
#include <limits.h>
#if CHAR_BIT != 8
#error char is expected to be 8 bits
#endif
unsigned char RevByte(unsigned char b)
{
static const unsigned char t[16] =
{
0x0, 0x8, 0x4, 0xC, 0x2, 0xA, 0x6, 0xE,
0x1, 0x9, 0x5, 0xD, 0x3, 0xB, 0x7, 0xF
};
return t[b >> 4] | (t[b & 0xF] << 4);
}
void RevBytes(unsigned char* b, size_t c)
{
size_t i;
for (i = 0; i < c / 2; i++)
{
unsigned char t = b[i];
b[i] = RevByte(b[c - 1 - i]);
b[c - 1 - i] = RevByte(t);
}
if (c & 1)
b[c / 2] = RevByte(b[c / 2]);
}
int main(void)
{
int i;
unsigned char buf[16] =
{
0x0, 0x8, 0x4, 0xC, 0x2, 0xA, 0x6, 0xE,
0x1, 0x9, 0x5, 0xD, 0x3, 0xB, 0x7, 0xF
};
RevBytes(buf, 16);
for (i = 0; i < 16; i++)
printf("0x%02X ", buf[i]);
puts("");
return 0;
}
输出(ideone):
0xF0 0xE0 0xD0 0xC0 0xB0 0xA0 0x90 0x80 0x70 0x60 0x50 0x40 0x30 0x20 0x10 0x00
答案 1 :(得分:0)
反转集合的元素是一个老技巧 - 你先交换最后一个,然后是第一个+ 1和最后一个,然后......直到第一个+ i等于或者更接近集合而不是last-j。
你需要添加的就是
- 在交换之前翻转两个条目的位
- 如果你在中间留下一个元素,那么在现场翻转它的位
答案 2 :(得分:0)
要做到这一点 - 假设你的位反转方法是正确的 - 如果你可以在存储中省去额外的char
,你可以简单地遍历字节。请考虑以下方法:
static void swapReverseBytes(char* arr, size_t len)
{
int i = 0;
char tmp = 0;
if(arr == NULL || len < 1)
return;
if(len == 1) {
arr[0] = reverseByte(arr[0]);
return;
}
for(i = 0 ; i < (len / 2) ; ++i) {
tmp = arr[len - i - 1];
arr[len - i - 1] = reverseByte(arr[i]);
arr[i] = reverseByte(tmp);
}
}
这是一个粗略的草图(应该编译,我认为),并且,假设我没有一个一个错误,这应该工作。如前所述,使用LUT
反转位可能是最快的,但字节交换方法将相对类似,因为除非你保持关于数组遍历顺序的某些状态,否则你需要实际移动每个字节。如果是这种情况,很可能只需使用某种状态(即标志)来确定是否应该正常遍历数组(1...n
)或反向顺序(n...1
)。无论如何,交换在Big-O中是“免费的”,但在实践中可能(不一定)显示性能影响。因此,如果您的优化确实在速度上并且空间中的额外int
不是太多,那么这种状态对您来说可能是值得的。请注意,此技巧仅在内部使用时才有效。如果这种方法对用户公开并且他或她不知道该标志,那么这实际上不会翻转任何东西。使用此选项的另一个选择是,如果您可以使用C++
,则可以创建一个为用户封装此功能的类。
答案 3 :(得分:0)
要做到这一点 - 假设你的位反转方法是正确的 - 如果你可以在存储中省去额外的char
,你可以简单地遍历字节。请考虑以下方法:
static void swapReverseBytes(char* arr, size_t len)
{
int i = 0;
char tmp = 0;
if(arr == NULL || len < 1)
return;
if(len == 1) {
arr[0] = reverseByte(arr[0]);
return;
}
for(i = 0 ; i < (len / 2) ; ++i) {
tmp = arr[len - i - 1];
arr[len - i - 1] = reverseByte(arr[i]);
arr[i] = reverseByte(tmp);
}
}
这是一个粗略的草图(应该编译,我认为),并且,假设我没有一个一个错误,这应该工作。如前所述,使用LUT
反转这些位可能是最快的,但是字节交换相对类似,因为除非你保持关于数组遍历顺序的某些状态,否则你需要实际移动每个字节。如果是这种情况,很可能只需使用某种状态(即标志)来确定是否应该正常遍历数组(1...n
)或反向顺序(n...1
)。无论如何,交换是免费的&#34;在Big-O中,但在实践中可能(不一定)显示性能影响(因为没有&#34;实际&#34;交换字节顺序)。注意,如果用户期望一个排序的数组,这将不起作用 - 这个技巧只适用于这是内部的(或者你有某种封装,比如在C++
类中)。 / p>