I defined two variables:
uint8_t a[2];
uint16_t b;
Next I want to use a
as variable of type uint16_t
, e. g.
b = (uint16_t)a;
But this is wrong! My programs doesn't works correctly with such code. All is OK when I replace b
to uint8_t b[2]
and use elementwise operations.
Why?
Answer
a
is a pointer to an array of bytes. If you cast it to a uint16_t and assign it to b
, then b
will contain the address of the base of the array (where it is stored) in SRAM. If you want to treat the two bytes of the array a
as an integer, then use a union as suggested by user14284, but be aware that the union will represent the byte array in the memory byte ordering of the architecture (in AVR that would be little-endian, which means byte 0 is the least significant byte). The way to write that in code is:
union{
uint8_t a[2];
uint16_t b;
} x;
x.b[0] = 0x35;
x.b[1] = 0x4A;
// by virtue of the above two assignments
x.a == 0x4A35 // is true
Another way to do this without using a union is to cast a
to a uint16_t pointer and then dereference it like so:
uint8_t a[2] = {0x35, 0x4A};
uint16_t b = *((uint16_t *) a);
b == 0x4A35; // because AVR is little endian
If you are using the buffer to store big endian data (e.g. network byte order), then you'll need to byte-swap to use either of these techniques. A way to do that without any branches or temporary variables is:
uint8_t a[2] = {0x35, 0x4A};
a[0] ^= a[1];
a[1] ^= a[0];
a[0] ^= a[1];
a[0] == 0x4A; // true
a[1] == 0x35; // true
Incidentally this is not an AVR or even an embedded-only problem. Application level networking code written for PCs typically calls functions called htonl
, htons
(host to network, 32- and 16-bit variants) and ntohl
, ntohs
(network to host, 32- and 16-bit variants) whose implementations are target architecture dependent as to whether they swap the bytes or not (under the assumption that bytes as transmitted 'on the wire' are always big-endian when they are part of multi-byte words).
No comments:
Post a Comment