I have an array each of whose elements could be either uint16_t or a pair of uint8_t.
Its elements are defined as a union of a uint16_t and a sub-array of 2 uint8_t.
Unfortunately, the compiler (MicroChip XC16) allocates twice as much memory as it should for the array.
typedef union {
uint16_t u16; // As uint16_t
uint8_t u8[2]; // As uint8_t
} my_array_t;
my_array_t my_array[1]; // 1 word array, for testing
my_array[0].u8[0] = 1;
my_array[0].u8[1] = 2;
uint8_t byte_0 = my_array[0].u8[0]; // Gets 0x01
uint8_t byte_1 = my_array[0].u8[1]; // Gets 0x02
uint16_t byte_0 = my_array[0].u16; // Gets 0x0201
The compiler allocates 4 bytes instead of 2 bytes as it should.
Workaround: if I change the struct to:
typedef union {
uint16_t u16; // As uint16_t
uint8_t u8[1]; // As uint8_t
} my_array_t;
The compiler allocates 2 bytes as it should, but then this is incorrect:
my_array[0].u8[1] = 2;
though it still works:
uint8_t byte_1 = my_array[0].u8[1]; // Gets 0x02
(except for the inconvenience that the debugger doesn't show its value).
Question: should I live with the workaround, or should I use a better solution?
Please refer to a previous discussion on this, where the above solution was suggested.
EDIT.
Per EOF's suggestion (below), I checked sizeof.
Before the workaround:
sizeof(my_array_t) // Is 4
sizeof(my_array[0]) // Is 4
sizeof(my_array[0].u8) // Is 2
After the workaround:
sizeof(my_array_t) // Is 2
sizeof(my_array[0]) // Is 2
sizeof(my_array[0].u8) // Is 2
That would indicate that it's a compiler bug.
Instead of an array of 2 bytes, use a structure of 2 bytes:
// Two bytes in a 16-bit word
typedef struct{
uint8_t lsb; // As uint8_t, LSB
uint8_t msb; // As uint8_t. MSB
} two_bytes_t;
typedef union {
uint16_t u16; // As uint16_t
two_bytes_t u8x2; // As 2 each of uint8_t
} my_array_t;
my_array_t my_array[1]; // 1 word array, for testing
my_array[0].u8x2.msb = 1;
my_array[0].u8x2.lsb = 2;
The XC16 compiler correctly allocates only 2 bytes for each element, and the debugger correctly shows the individual bytes.