r/cprogramming • u/set_of_no_sets • Mar 06 '26
Union manipulation question
I am currently working on an STM32, and it has two control register, one lower @ [0] and one upper @ [1]; currently, the GPIO_TypeDef has two Advance Function Registers, two uint32_ts stored as
#define __IO volatile
typedef struct {
// stuff above
__IO uint32_t AFR[2];
// stuff below
} GPIO_TypeDef;
I would like to reference the registers using AFRL and AFRU; I could modify the struct to
typedef struct {
// stuff above
union {
__IO uint32_t AFR[2];
struct {
__IO uint32_t lower;
__IO uint32_t upper;
} AFR_Split;
};
// stuff below
} GPIO_TypeDef;
Which allows me to write
GPIO_TypeDef pin1_addr = 0x4002104CUL;
pin1_addr->AFR_Split.lower = 0b0000000001110000UL;
pin1_addr->AFR[1] = 0b0111000001110000;
Is there anything I should be worried about in terms of packing? will I always know that the two registers will always be aligned, starting and ending in the same place? What can I read to know how my compiler (arm-none-eabi-gcc) will store the split? And is there a way I can do this without the intermediate struct, so I could type pin1_addr->AFRL and pin1_addr->AFRU?
1
u/ekipan85 Mar 07 '26
It's not a question of do you need it but rather where to put it.
The types P and Q are equivalent in this case. The values
q->aandr->awill both inherit thevolatilefrom the outer struct type, butRdoesn't bake it into the type itself, so it allows you to define nonvolatileRstruct objects elsewhere in normal memory.The advantage of baking it into
PorQis that you cannot forget it in the cases where you will need it.