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?

Mooing Duck
  • 64,318
  • 19
  • 100
  • 158
Eternal Learner
  • 3,800
  • 13
  • 48
  • 78

1 Answers1

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.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • Sorry I meant `len = *(uint16_t*)buf` . – Eternal Learner Feb 01 '18 at 20:43
  • @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. – Sergey Kalinichenko Feb 01 '18 at 20:46
  • so would there be a difference between memcopy and doing this assignment copy? If yes, what would that be? Which method is preferred? – Eternal Learner Feb 01 '18 at 20:49
  • @EternalLearner: This post describes the differences, ergo yes there are differences. This post also describes why one works and why the other doesn't, so presumably the one that works is preferred. – Mooing Duck Feb 01 '18 at 20:50
  • Also, assuming I did not pad this struct (if I get this over the network) would the above method be safe? – Eternal Learner Feb 01 '18 at 20:50
  • 1
    @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`. – Sergey Kalinichenko Feb 01 '18 at 20:54
  • 2
    @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. – WhozCraig Feb 01 '18 at 20:54