Parsing a binary message in C ++. Any lib with examples?

I am looking for any example library by analyzing binary msg in C ++. Most people request reading a binary file or data received on a socket, but I just have a set of binary messages that I need to decode. Someone said boost :: spirit , but I could not find a suitable example for my needs.

As an example: 9A690C12E077033811FFDFFEF07F042C1CE0B704381E00B1FEFFF78004A92440

where the first 8 bits are the preamble, the next 6 bits are the msg identifier (integer from 0 to 63), the next 212 bits are data, and the last 24 bits are CRC24.

So, in this case msg 26, I have to get this data from 212 data bits:

  • 4-bit integer value
  • 4-bit integer value
  • 9 bit floating point value from 0 to 63.875, where LSB is 0.125
  • 4-bit integer value

EDIT: I need to work at the bit level, so memcpy is not a good solution, as it copies a few bytes. To get the first 4-bit integer value, I have to get 2 bits from the byte, and 2 more bits from the next byte, shift each pair and make up. What I'm asking for is a more elegant way to extract values, because I have about 20 different messages and you want a general solution for analyzing them at the bit level.

And so on.

Do you know os any library that can easily achieve this?

I also found another Q / A that uses static_cast. I thought it over, and for every person recommending this approach, there is another warning about the installations. Since I already have my message, I don’t know if this warning applies to me or just for socket communication.

EDIT: boost: dynamic_bitset looks promising. Any help to use?

+4
source share
3 answers

If you cannot find a common library to parse your data, use bit fields to get the data and memcpy () into the struct variable. See Battle Link . This will be more optimized for your application.

Remember to pack the structure.

Example:

 #pragma pack include "order32.h" struct yourfields{ #if O32_HOST_ORDER == O32_BIG_ENDIAN unsigned int preamble:8; unsigned int msgid:6; unsigned data:212; unsigned crc:24; #else unsigned crc:24; unsigned data:212; unsigned int msgid:6; unsigned int preamble:8; #endif }/*__attribute__((packed)) for gcc*/; 

You can do a small compile-time check to see if your computer uses LITTLE ENDIAN or BIG ENDIAN. After that, define it in the PREPARATION SYMBOL ::

 //order32.h #ifndef ORDER32_H #define ORDER32_H #include <limits.h> #include <stdint.h> #if CHAR_BIT != 8 #error "unsupported char size" #endif enum { O32_LITTLE_ENDIAN = 0x03020100ul, O32_BIG_ENDIAN = 0x00010203ul, O32_PDP_ENDIAN = 0x01000302ul }; static const union { unsigned char bytes[4]; uint32_t value; } o32_host_order = { { 0, 1, 2, 3 } }; #define O32_HOST_ORDER (o32_host_order.value) #endif 

Thanks to the code from Christoph @ here

Example program for using bit fields and their outputs:

 #include <iostream> #include <cstdio> #include <cstdlib> #include <memory.h> using namespace std; struct bitfields{ unsigned opcode:5; unsigned info:3; }__attribute__((packed)); struct bitfields opcodes; /* info: 3bits; opcode: 5bits;*/ /* 001 10001 => 0x31*/ /* 010 10010 => 0x52*/ void set_data(unsigned char data) { memcpy(&opcodes,&data,sizeof(data)); } void print_data() { cout << opcodes.opcode << ' ' << opcodes.info << endl; } int main(int argc, char *argv[]) { set_data(0x31); print_data(); //must print 17 1 on my little-endian machine set_data(0x52); print_data(); //must print 18 2 cout << sizeof(opcodes); //must print 1 return 0; } 
+6
source

You can manipulate bits for your own, for example, to parse a 4-bit integer value:

 char[64] byte_data; size_t readPos = 3; //any byte int value = 0; int bits_to_read = 4; for (size_t i = 0; i < bits_to_read; ++i) { value |= static_cast<unsigned char>(_data[readPos]) & ( 255 >> (7-i) ); } 

Floats are usually sent as string data:

 std::string temp; temp.assign(_data+readPos, 9); flaot value = std::stof(temp); 

If your data contains a custom float format, just extract the bits and do your math:

 char[64] byte_data; size_t readPos = 3; //any byte float value = 0; int i = 0; int bits_to_read = 9; while (bits_to_read) { if (i > 8) { ++readPos; i = 0; } const int bit = static_cast<unsigned char>(_data[readPos]) & ( 255 >> (7-i) ); //here your code ++i; --bits_to_read; } 
+1
source

Here is a good article that describes several solutions to the problem.

It even contains a reference to the ibstream class created by the author specifically for this purpose (the link seems dead, though). The only mention of this class that I could find is in the C ++ bit library here - maybe this is what you need, although it is not popular and it is under the GPL.

In any case, boost::dynamic_bitset may be the best choice as it is time-tested and community-tested. But I have no personal experience.

0
source

Source: https://habr.com/ru/post/1441223/


All Articles