简体   繁体   中英

How do I deserialise a const byte * to a structure in cpp?

I have a structure like this

struct foo {
 string                str1;
 uint16_t              int1
 string                str2;
 uint32_t              int2;
 string                str3;   
 };

strings str1, str2, str3 are of fixed length of 12 bytes, 3 bytes,etc. left padded with spaces.

I have a function void func(const byte* data, const size_t len) which is supposed to convert the byte * data to structure foo. len is length of data. What are the ways in which I can do this?

Again the data is const pointer of byte type and will not have null characters in between to distinguish different members. Should I use character array instead of string for str1, str2, str3?

Easiest (but most errorprone) way is to just reinterpret_cast / std::memcpy if the strings have fixed length:

// no padding
#pragma pack(push, 1)
struct foo {
 char       str1[12];
 uint16_t   int1;
 char       str2[3];
 uint32_t   int2;
 char       str3[4];   
 };
#pragma pack(pop)

void func(const byte* data, const size_t len) {
    assert(len == sizeof(foo));

    // non owning
    const foo* reinterpreted = reinterpret_cast<const foo*>(data);

    // owning
    foo reinterpreted_val = *reinterpret_cast<const foo*>(data);
   
    foo copied;
    memcpy(&copied, data, len); 
}

Notes:

Slightly better approach:

struct foo {
 char       str1[13];
 uint16_t   int1;
 char       str2[4];
 uint32_t   int2;
 char       str3[5];   
 };

void func(const char* data, const size_t len) {
    foo f;

    memcpy(f.str1, data, 12);
    f.str1[12] = '\0';
    data+=12;

    memcpy(&f.int1, data, sizeof(uint16_t));
    data+=sizeof(uint16_t);

    memcpy(f.str2, data, 3);
    f.str2[3] = '\0';
    data+=3;

    memcpy(&f.int2, data, sizeof(uint32_t));
    data+=sizeof(uint32_t);

    memcpy(f.str3, data, 4);
    f.str3[4] = '\0';
    data+=4;
}

Notes:

  • You could combine both approaches to get rid of the pointer arithmetic. That would also account for any padding in your struct you might have.
  1. I think the easiest way to do this is to change the string inside the structure to the type of char. Then you can easily copy the objects of this structure according to its size.
  2. you will have to somehow deal with the byte order on machines with different byte order
struct foo {
    char                str1[12];
    uint16_t              int1;
    char                str2[3];
    uint32_t              int2;
    char                str3[5];
};

byte* Encode(foo* p, int Size) {
    int FullSize = Size * sizeof(foo);
    byte* Returner = new byte[FullSize];

    memcpy_s(Returner, FullSize, p, FullSize);

    return Returner;
}

foo * func(const byte* data, const size_t len) {
    int ArrSize = len/sizeof(foo);

    if (!ArrSize || (ArrSize* sizeof(foo)!= len))
        return nullptr;

    foo* Returner = new foo[ArrSize];

    memcpy_s(Returner, len, data, len);

    return Returner;
}

int main()
{
    const size_t ArrSize = 3;
    foo Test[ArrSize] = { {"Test1",1000,"TT",2000,"cccc"},{"Test2",1001,"YY",2001,"vvvv"},{"Test1",1002,"UU",2002,"bbbb"}};
    foo* Test1 = nullptr;

    byte* Data = Encode(Test, ArrSize);

    Test1 = func(Data, ArrSize * sizeof(foo));

    if (Test1 == nullptr) {
        std::cout << "Error extracting data!" << std::endl;
        delete [] Data;
        return -1;
    }

    std::cout << Test1[0].str1 << " " << Test1[1].str1 << " " << Test1[2].str3 << std::endl;

    delete [] Data;
    delete[] Test1;

    return 0;
}

output

Test1 Test2 bbbb

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM