Force struct member alignment (with IAR compiler)

0

Consider this typedef:

#pragma pack(4)
typedef struct
{
  uint8  dataArea0[11];
  uint8  dataArea1[12];
  uint8  dataArea2[13];
  uint8  dataArea3[14];

} myStruct;

I have some non-2^n sized arrays that I'd like to use from other libs. From those libs these dataAreas can be cast as e.g., structs or whatever i need. The problem occurs when one of these struct members land on a non 4-byte aligned address AND contain data types that are not happy about their address alignment.

Therefore I'd like to force the alignment with the pack pragma, but this does not help (at least in the IAR compiler -- from the manual: Use this pragma directive to specify the maximum alignment of struct and union members.). I also tried to use the data_alignment pragma, but this seems to be for variables and not struct members.

Does anyone know a nice compiler trick to force the alignment of the struct members?

Quicklink to compiler manual for those interested: IAR AVR32 Compiler Ref

Edit: I ended up using this as an alternative

#define ROUND_UP_NEXT_FOUR(x) ((x + 3) & ~0x03)

typedef struct
{
  uint8  dataArea0[ROUND_UP_NEXT_FOUR(11)];
  uint8  dataArea1[ROUND_UP_NEXT_FOUR(12)];
  uint8  dataArea2[ROUND_UP_NEXT_FOUR(13)];
  uint8  dataArea3[ROUND_UP_NEXT_FOUR(14)];

} myStruct;

In this way I'm sure that the padding will take place at a 4-aligned address.

Edit2:

An example of how this can go wrong:

struct otherStruct
{
  uint16 dataBuf0;
  uint32 dataBuf1;
  uint32 dataBuf2;
  uint32 dataBuf3;
  uint32 dataBuf4[10];
};

myStruct* myStructInstance = 0x00000000; //some address
//address of this is 0x0B
struct otherStruct* oS = (struct otherStruct*) myStructInstance.dataArea1;
//we assign to a 2 byte variable that is 
//located at address that is not 2 byte aligned -> error!
os->dataBuf0 = 10; 

In this case we get a runtime error (worst (or best?) case, crash).

c
compilation
iar
asked on Stack Overflow Sep 19, 2019 by SupAl • edited Sep 21, 2019 by SupAl

1 Answer

1

Unfortunately the IAR AVR32 compiler does not support the _Alignas keyword. However, when IAR language extensions are enabled it supports anonymous unions and this can be used to force the alignment of individual fields of a struct. The trick is that the alignment of a union is the strictest (largest) alignment of any of its fields. Thus, by wrapping each field dataArea? in an anonymous union with a dummy field with 32-bit alignment it is possible to force the alignment of each dataArea? field to 32-bit. An example is shown below. It include both raw anonymous-union declarations as well as macro-magic to simplify declaration when the number of fields is large.

#include <stdint.h>

#define GLUE_B(x,y) x##y
#define GLUE(x,y) GLUE_B(x,y)

#define ALIGNED(FIELD, ALIGN_TYPE) union { FIELD; ALIGN_TYPE GLUE(a,__LINE__); }
#define ALIGNED32(FIELD) ALIGNED(FIELD, uint32_t)

typedef struct
{
  ALIGNED(uint8_t dataArea0[11], uint32_t);
  ALIGNED32(uint8_t dataArea1[12]);
  union { uint8_t dataArea2[13]; uint32_t a2;};
  union { uint8_t dataArea3[12]; uint32_t a3;};
} myStruct;
answered on Stack Overflow Sep 23, 2019 by Johan

User contributions licensed under CC BY-SA 3.0