djk - In general different processors can (and do) represent the same data types in different ways. Then different compilers, or different compiler settings, can pack data in different ways. Network protocols, like TCP/IP have to solve this problem.
The first variation is ARM processors can store multi-byte numbers in a different byte order to the way x86 and x86-64 store multi-byte numbers.
Another variation is a compiler for the same architecture might pack data with some compiler options, and not pack the data in the same way with different compiler options.
As jcsalomon wrote don't try to send a struct in one chunk.
So, to make a binary data stream to be predictable, copy the data to a byte buffer.
That will ensure that code, that you control, lays the data out and you can remove dependencies on the compiler and processor.
For example, the host processor might store a multi-byte number (e.g. UINT16) with the 'high' part of the number in the byte with a high address, while the Maple might store it in the byte with the low address.
So, you might code it as (written on Mac, haven't got Maple next to me):
#include <stdio.h>
#include <stdint.h>
/** packing functions
*/
const int isSameEdian = 1; // Preserve endian of numbers
uint8_t* pack_uint8_t(uint8_t* dest, const uint8_t value);
uint8_t* pack_uint16_t(uint8_t* dest, const uint16_t value);
struct Tester
{
uint8_t header;
uint16_t packetType;
uint16_t command;
} tester = { 'c', 0x00ff, 1234 };
int main (int argc, const char * argv[]) {
uint8_t buff[sizeof(tester)];
uint8_t* buffptr = &buff[0];
buffptr = pack_uint8_t(buffptr, tester.header);
buffptr = pack_uint16_t(buffptr, tester.packetType);
buffptr = pack_uint16_t(buffptr, tester.command);
printf("Size=%d\n", buffptr-buff);
for (int i=0; i<buffptr-buff; ++i) {
printf("%#4x ", buff[i]);
}
printf("\n");
return 0;
}
uint8_t* pack_uint8_t(uint8_t* dest, const uint8_t value) {
dest[0] = value;
return dest + sizeof(value);
}
uint8_t* pack_uint16_t(uint8_t* dest, const uint16_t value) {
uint8_t* valueptr = (uint8_t*)&value;
if (isSameEdian) {
dest[0] = valueptr[0]; // Warning: preserves endian
dest[1] = valueptr[1]; // Warning: preserves endian
} else {
dest[0] = valueptr[1]; // Warning: CHANGES endian
dest[1] = valueptr[0]; // Warning: CHANGES endian
}
return dest+ sizeof(value);
}
This example gives a mechanism to guarantee the packing and byte order independent of the underlying processor or compiler.
Change isSameEdian
to isSameEdian = 0
and you'll get the other byte ordering for multi-byte numbers.
It happens that ARM Cortex-M3 can handle misaligned numbers, but other members of the ARM family, and some other processors can not handle misaligned numbers. Hence IMHO it is better to avoid relying on a particular processor+compiler+compiler-settings properties. (Code tends to get reused.)