如何使用指针数组反转数据(解析二进制文件)

时间:2010-06-26 21:28:19

标签: c++ pointers arrays reverse endianness

我正在使用规范解析二进制文件。该文件以big-endian模式进行,因为它已经累积了流式传输数据包。我必须反转数据包的长度,以便将它们“重新解释”为正确的变量类型。 (我无法使用net / inet.h函数,因为数据包的长度不同。)

ifstream类的read()方法将字节放在图表指针数组中。我尝试使用a手动进行回归,但我无法弄清楚如何通过“指针列表”来改变它们在数组中的位置。

如果有人知道更有效的方法,请告诉我(需要解析8GB的数据)。

#include <iostream>
#include <fstream>

void reverse(char &array[]);

using namespace std;

int main ()
{
    char *a[5];
    *a[0]='a'; *a[1]='b'; *a[2]='c'; *a[3]='d'; *a[4]='e';

    reverse(a);

    int i=0;
    while(i<=4)
    {
        cout << *a[i] << endl;
        i++;
    }
    return 0;
}
void reverse(char &array[])
{
    int size = sizeof(array[])+1;
    //int size = 5;
    cout << "ARRAY SIZE: " << size << endl;

    char aux;
    for (int i=0;i<size/2;i++)
    {
            aux=array[i];
            array[i]=array[size-i-1];
            array[size-i-1]=aux;
    }
}

感谢各位的帮助!

2 个答案:

答案 0 :(得分:2)

不完全。

  

该文件采用big-endian模式,因为它已经累积了流式传输数据包。我必须反转数据包的长度,以便将它们“重新解释”为正确的变量类型。

您需要反转存储数据级别的字节,而不是文件而不是数据包。

例如,如果文件存储结构。

struct S {
  int i;
  double d;
  char c;
};

读取你需要反转的结构:

int: [4321]->[1234]  // sizeof(int) == 4, swap the order of 4 bytes
double: [87654321]->[12345678]  // sizeof(double) == 8, swap the order of 8 bytes
char: [1]->[1]  // sizeof(char) == 1, swap 1 byte (no swapping needed)

不是整个结构。

不幸的是,它并不像只是反转文件中的数据块或文件本身那样微不足道。您需要确切地知道存储的数据类型,并反转其中的字节。

inet.h中的函数用于此目的,因此我建议您使用它们。

所以,这将我们带到c字符串。如果您将c字符串存储在文件中,是否需要交换其字节序?好吧,c字符串是1字节char s的序列。您不需要交换1个字节char,因此您不需要交换c字符串中的数据!

如果您真的想要交换6个字节,可以使用std::reverse函数:

char in[6] = get6bytes();
cout << in << endl;  // shows abcdef 
std::reverse(in, in+6);
cout << in << endl;  // shows fedcba

如果您在任何大规模(大量类型)上执行此操作,那么您可能需要考虑编写生成这些字节交换函数(和文件读取函数)的代码生成器,它也不是 很难,只要你能找到一个工具来解析c中的结构(我已使用gcc-xml为此,或者clang可能有帮助。)

这使序列化成为一个更难的问题。如果它掌握了您的权力,您可能需要考虑使用XML或Google的协议缓冲来为您解决这些问题。

答案 1 :(得分:0)

好的,在您发表评论后,我明白您的意思。因此,您需要更改6字节宽的字段的字节顺序。

我认为this article应该对您和this question on SO有所帮助,它展示了如何以不同的方式实现转换,最快的是按位实现。它没有显示六字节宽字段的实现,但可以轻松地制作类似的解决方案。

我建议在64位整数中复制长度字段,然后实现自定义函数来交换相关的6个字节。在任何情况下摆脱或所有的char指针......;)

如果您正在编译VC ++,则有以下功能:_byteswap_uint64。超过这个uint64高端的6个字节,调用这个函数和hopla,你就完成了。

在凌晨4:12编辑(我一定非常沉迷于stackoverflow)

#include <iostream>
#include <stdlib.h>

typedef unsigned char    byte;
typedef unsigned __int64 uint64_t; // uncomment if you are not on VC++

// in case you are not compiling with VC++ use this custom function
// It can swap data of any size. Adapted from:
// https://stackoverflow.com/questions/2182002/convert-big-endian-to-little-endian-in-c-without-using-provided-func/2182581#2182581
// see: http://en.wikipedia.org/wiki/XOR_swap_algorithm

void
swapBytes( void* v, size_t n )
{
   byte* in = (byte*) v;

   for( size_t lo=0, hi=n-1; hi>lo; ++lo, --hi )

      in[lo] ^= in[hi]
   ,  in[hi] ^= in[lo]
   ,  in[lo] ^= in[hi] ;
}

#define SWAP(x) swapBytes( &x, sizeof(x) );


int
main()
{
   // pointer to location of length field. 
   // You will have to read it from file to memory.
   byte length[6] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 };

   // ok, you have read it from file, now get it in an uint64_t
   uint64_t i = *( (uint64_t*)  length );

   i <<= 16; // zero two bytes and move everything to the high end.

   std::cout << std::hex << i                     << std::endl;
   std::cout << std::hex << _byteswap_uint64( i ) << std::endl;

   // generic swapping function
   SWAP( i ) 
   std::cout << std::hex << i                     << std::endl;

   std::cin.get();
   return 0;
}

// Outputs:
// 605040302010000
// 10203040506
// 10203040506