4
Struct A
{
   uint16_t len;
   uint8_t  cnt;
   uint8_t  unit;
   uint32_t seq; 
};

This struct A is serialized into a char * buf. If I want to deserialize the individual values eg:

uint16_t len = 0;
memcpy(&len, buf, sizeof(len));

or I can just do

uint16_t len = (uint16_t) buf;

Which one is better or are both the same?

Also to deserialize the whole struct, if I just do

A tmp;

memcpy(&tmp, buf, sizeof(A));

Would this work fine or should I be worried about padding etc from the compiler?

4
  • 8
    You probably meant len = *(uint16_t*)buf. Well, that's a strict aliasing rule violation. Commented Feb 1, 2018 at 20:37
  • What's a strict aliasing rule violation? Commented Feb 1, 2018 at 20:44
  • 2
    This is another question, which is actually already answered multiple times. stackoverflow.com/questions/98650/… Commented Feb 1, 2018 at 20:45
  • is the C++ tag relevant? Commented Feb 1, 2018 at 20:45

1 Answer 1

8

When the data is copied into char[] buffer, it may not be properly aligned in memory for access as multi-byte types. Copying the data back into struct restores proper alignment.

If I want to deserialize the individual values eg:

uint16_t len = 0;
memcpy(&len, buf, sizeof(len));

Assuming that you have copied the struct into buf, this is perfectly valid, because the language guarantees that the initial member would be aligned with the beginning of the structure. However, casting buf to uint16_t* is invalid, because the buffer many not be properly aligned in memory to be addressed as uint16_t.

Note that getting elements of the struct other than the initial one require computing proper offset:

uint32_t seq;
memcpy(&seq, buf+offsetof(struct A, seq), sizeof(seq));

Also to deserialize the whole struct, if I just do

A tmp;
memcpy(&tmp, buf, sizeof(A));

Would this work fine or should I be worried about padding etc from the compiler?

This would work fine. Any padding embedded in the struct when you copied it into the buf would come back into tmp, along with the actual data.

Sign up to request clarification or add additional context in comments.

7 Comments

Sorry I meant len = *(uint16_t*)buf .
@EternalLearner Yes, I assumed that you meant to cast to pointer and dereference, that's why I wrote about casting buf to uint16_t* pointer.
so would there be a difference between memcopy and doing this assignment copy? If yes, what would that be? Which method is preferred?
@EternalLearner If you get the struct over the network, the method would be unsafe, unless the sender uses compatible hardware. If it does not, you would need to work out some protocol with ntoh/hton.
@EternalLearner ideally, you develop a formal protocol for transmitting the data serially (over network, or otherwise), then comply with that protocol with both the sender and the receive. Doing so has the added advantage, if you set up the protocol wisely, of being platform-independent; something which struct-dumping into a buffer, sending, then buffer-dumping into a struct, is sorely lacking.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.