Tool/software: TI C/C++ Compiler
Hi all,
Using compiler TI v16.9.7.LTS.
I've come across a problem where the packed attribute doesn't seem to work depending on exactly where it is placed.
Here is a code example that illustrates the issue
/* DriverLib Includes */
#include <ti/devices/msp432p4xx/driverlib/driverlib.h>
/* Standard Includes */
#include <stdint.h>
#include <stdbool.h>
typedef struct st_outerStruct_1
{
union
{
uint8_t rawData[6];
struct st_innerSt1
{
// Byte 1
uint8_t byte1_bit1 : 1;
uint8_t byte1_bit2 : 1;
uint8_t byte1_bit3 : 1;
uint8_t byte1_bit4 : 1;
uint8_t byte1_bit5 : 1;
uint8_t byte1_bit6 : 1;
uint8_t byte1_bit7 : 1;
uint8_t byte1_bit8 : 1;
// Byte 2
uint8_t byte2_bit1 : 1;
uint8_t byte2_bit2 : 1;
uint8_t byte2_bit3 : 1;
uint8_t byte2_bit4 : 1;
uint8_t byte2_bit5 : 1;
uint8_t byte2_bit6 : 1;
uint8_t byte2_bit7 : 1;
uint8_t byte2_bit8 : 1;
// Byte 3,4,5,6
uint32_t number_u32;
} innerSt1 __attribute__ ((__packed__));
} __attribute__ ((__packed__));
} outerStruct_1;
typedef struct st_outerStruct_2
{
union
{
uint8_t rawData[6];
struct __attribute__ ((__packed__)) st_innerSt2
{
// Byte 1
uint8_t byte1_bit1 : 1;
uint8_t byte1_bit2 : 1;
uint8_t byte1_bit3 : 1;
uint8_t byte1_bit4 : 1;
uint8_t byte1_bit5 : 1;
uint8_t byte1_bit6 : 1;
uint8_t byte1_bit7 : 1;
uint8_t byte1_bit8 : 1;
// Byte 2
uint8_t byte2_bit1 : 1;
uint8_t byte2_bit2 : 1;
uint8_t byte2_bit3 : 1;
uint8_t byte2_bit4 : 1;
uint8_t byte2_bit5 : 1;
uint8_t byte2_bit6 : 1;
uint8_t byte2_bit7 : 1;
uint8_t byte2_bit8 : 1;
// Byte 3,4,5,6
uint32_t number_u32;
} innerSt2;
} __attribute__ ((__packed__));
} outerStruct_2;
typedef struct st_outerStruct_3
{
union
{
uint8_t rawData[6];
struct
{
// Byte 1
uint8_t byte1_bit1 : 1;
uint8_t byte1_bit2 : 1;
uint8_t byte1_bit3 : 1;
uint8_t byte1_bit4 : 1;
uint8_t byte1_bit5 : 1;
uint8_t byte1_bit6 : 1;
uint8_t byte1_bit7 : 1;
uint8_t byte1_bit8 : 1;
// Byte 2
uint8_t byte2_bit1 : 1;
uint8_t byte2_bit2 : 1;
uint8_t byte2_bit3 : 1;
uint8_t byte2_bit4 : 1;
uint8_t byte2_bit5 : 1;
uint8_t byte2_bit6 : 1;
uint8_t byte2_bit7 : 1;
uint8_t byte2_bit8 : 1;
// Byte 3,4,5,6
uint32_t number_u32;
} __attribute__ ((__packed__));
} __attribute__ ((__packed__));
} outerStruct_3;
int main(void)
{
outerStruct_1 st1; // Inner struct is named, packed attribute at the END of the inner struct
outerStruct_2 st2; // Inner struct is named, packed attribute at the START of the inner struct
outerStruct_3 st3; // Inner struct is NOT named, packed attribute at the END of the inner struct
st1.innerSt1.number_u32 = 0xaabbccdd; // rawData field is wrong - the upper 2 bytes have been dropped - looks like number_u32 has been 32bit aligned.
st2.innerSt2.number_u32 = 0xaabbccdd; // rawData field is right
st3.number_u32 = 0xaabbccdd; // rawData field is right
while(1){}
}
In the above code I have three nearly identically defined structs. Within each struct I use a union so that I can look at the raw bytes.
In this particular example, the outer struct is probably redundant, but in my full code I have additional fields inside the outer struct (not just the union) so I've left the outer struct in place.
After running the above code, I would execpt rawData[2] = 0xdd, rawData[3] = 0xcc, rawData[4] = 0xbb rawData[5] = 0xaa for st1, st2 and st3
But for st1 it seems the compiler has 32bit aligned number_u32 so I get rawData[2] = 0x00, rawData[3] = 0x00, rawData[4] = 0xdd rawData[5] = 0xcc.
This problem only seems to happen if you (a) name the inner structure AND (b) put the attribute at the end of the inner structure definition.
Is this expected behaviour? If it is, could you please point me to appropriate documentation on how the packed attribute works? I'd like to understand just what is going on so I can avoid this issue in future.
Cheers
Julian