Reputation: 60
I am decoding a serial protocol. The data is sent from a device in little-endian format over the wire. I have hacked together two different ways of doing it but they both seem very "hacky".
// Example of data that is read in from serial port
unsigned char data[8] = {0xb0,0x00,0x44,0x04,0x4a,0x0f,0x4d,0x30};
// This will pull out the number that I need (on a little-endian machine)
uint16_t a;
a = *(uint16_t*)&data[2];
//So will this, but it makes an extra call to memcpy(). (again, only on a little-endian machine)
uint16_t b;
memcpy((void*)&b,(void*)&data[2],sizeof(b));
I have code that I can plug in to swap bytes for big endian machines
#ifdef WORDS_BIGENDIAN
unsigned char *word_ptr;
word_ptr = &data[2];
// swap bytes, standard XOR swap algorithm
word_ptr[0] = word_ptr[0] ^ word_ptr[1];
word_ptr[1] = word_ptr[1] ^ word_ptr[0];
word_ptr[0] = word_ptr[0] ^ word_ptr[1];
#endif /* WORDS_BIGENDIAN */
An older question brought this up: memcpy vs pointer cast for reading BLE sensor float but the accepted answer only confirmed that it could work on certain platforms and comments indicated the behavior was undefined. What is a better way of doing this?
Upvotes: 0
Views: 463
Reputation: 141638
Normal procedure would be:
uint16_t a = data[2] + data[3] * 0x100u;
Some people prefer bitshift instead of multiplication but the result is the same.
The memcpy version probably doesn't "make an extra call to memcpy", memcpy optimization is a pretty basic and widespread compiler feature. But it has different behaviour depending on endianness of the local machine.
The *(uint16_t) *
version does cause undefined behaviour as you say.
The XOR swap is considered poor form and it's better to swap using a temporary variable . Write simple and maintanable code and let the compiler do its job.
Upvotes: 3