Easiest way to read binary data from std :: vector <unsigned char>?

I have a piece of binary data in a form const std::vector<unsigned char>, and you want to be able to extract individual fields from it, such as 4 bytes for an integer, 1 for booleans, etc. It should be as effective and simple as possible. eg. It should be able to read data in place without the need for copying it (for example, to a string or array). And it should be able to read one field at a time, for example, a parser, since a piece of data does not have a fixed format. I already know how to determine which type of field to read in each case - the problem is that it uses a useful interface on top std::vector.

However, I cannot find an easy way to get this data in an easily accessible form that gives me useful reading functions. eg. std::basic_istringstream<unsigned char>gives me a read interface, but it seems to me that I need to copy the data to a temporary one first std::basic_string<unsigned char>, which is not an idea for large data blocks.

There may be some way to use streambuf in this situation to read data in place, but it seems I would need to create my own streambuf class for this.

It seems to me that I can probably just use sscanf for vector data (), and this will seem shorter and more efficient than alternatives to the standard C ++ library. EDIT: Having been reminded that sscanf is not doing what I mistakenly thought it was, I really don't know how to do this in C or C ++. But I'm missing something, and if so, then what?

+3
source share
5 answers

You have access to the data in the vector through it operator[]. Vector data is stored in one continuous array, and []returns a link to an element of this array. You can use this link directly or through memcpy.

std::vector<unsigned char> v;
...
byteField = v[12];
memcpy(&intField, &v[13], sizeof intField);
memcpy(charArray, &v[20], lengthOfCharArray); 

EDIT 1: If you want something “more convenient” that you can try:

template <class T>
ReadFromVector(T& t, std::size_t offset, 
  const std::vector<unsigned char>& v) {
  memcpy(&t, &v[offset], sizeof(T));
}

Using:

std::vector<unsigned char> v;
...
char c;
int i;
uint64_t ull;
ReadFromVector(c, 17, v);
ReadFromVector(i, 99, v);
ReadFromVector(ull, 43, v);

EDIT 2:

struct Reader {
  const std::vector<unsigned char>& v;
  std::size_t offset;
  Reader(const std::vector<unsigned char>& v) : v(v), offset() {}
  template <class T>
  Reader& operator>>(T&t) {
    memcpy(&t, &v[offset], sizeof t);
    offset += sizeof t;
    return *this;
  }
  void operator+=(int i) { offset += i };
  char *getStringPointer() { return &v[offset]; }
};

Using:

std::vector<unsigned char> v;
Reader r(v);
int i; uint64_t ull;
r >> i >> ull;
char *companyName = r.getStringPointer();
r += strlen(companyName);
+4

, , . :

struct MyData {
    int intVal;
    bool boolVal;
    char[15] stringVal;
} __attribute__((__packed__));

// assuming all extracted types are prefixed with a one byte indicator.
// Also assumes "vec" is your populated vector
int pos = 0;
while (pos < vec.size()-1) {
    switch(vec[pos++]) {
        case 0: { // handle int
            int intValue; 
            memcpy(&vec[pos], &intValue, sizeof(int));
            pos += sizeof(int); 
            // do something with handled value
            break;
        }
        case 1: { // handle double
            double doubleValue; 
            memcpy(&vec[pos], &doubleValue, sizeof(double));
            pos += sizeof(double); 
            // do something with handled value
            break;
        }
        case 2: { // handle MyData
            struct MyData data; 
            memcpy(&vec[pos], &data, sizeof(struct MyData));
            pos += sizeof(struct MyData); 
            // do something with handled value
            break;
        }
        default: {
            // ERROR: unknown type indicator
            break;
        }
    }
}
+1

, sscanf , . bool

bool b = my_vec[10];

int, ( , int 32 ):

unsigned int i = my_vec[10] << 24 | my_vec[11] << 16 | my_vec[12] << 8 | my_vec[13];

16- unsigned short :

 unsigned short s = my_vec[10] << 8 | my_vec[11];¨
+1

Qt, QByteArray fromRawData() constructor, QByteArray . QTextStream.

- (, streambuf), , :)

+1

for . , char :

int myInt = vec[0] & 0xF0;

, , :

bool myBool = vec[0] & 0x08;

The three least significant (least significant) bits can be connected like this:

int myInt2 = vec[0] & 0x07;

Then you can repeat this process (using the for loop) for each element of your vector.

0
source

All Articles