字节交换/反转字符数组

时间:2013-02-25 04:20:15

标签: c arrays char reverse

我正在寻找一种方法来反转字符数组中的字节。我还需要在将它们放在正确位置之前反转被交换字节的各个位。 例如说我有一个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。这是正确的方法吗?有没有更好的方法来实现这一目标? 任何帮助将不胜感激。

4 个答案:

答案 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>