This is a badly designed warning from GCC.
When you apply the packed
attribute to a structure, it makes the alignment requirement of its members one byte. Thus, when you take the address of a uint32_t
member, what you get is not a uint32_t *
but a uint32_t __attribute__ ((__aligned__(1))) *
.1 It would be valid to assign this address to a uint32_t __attribute__ ((__aligned__(1))) *
or (with a cast) to an unsigned char *
.
Thus, ideally, the compiler would not warn you when you take the address of the member but rather when you use it in a way that requires greater alignment than it is guaranteed to have. Implementing such a warning may have been difficult at the time support for packed structures was created and this warning was added.
In this code:
st_t st;
st_t * st_p = &st;
st_p->b = 0;
the address of an st_t
is taken and is assigned to an st_t *
, so there is no problem. Then st_p->b
accesses the member b
but does not take its address, so there is no hazard that an unaligned address may be used as a pointer to an aligned address, so no warning is needed.
Footnote
1 GCC’s aligned
attribute only allows increasing the alignment requirement of a type, not decreasing it. packed
can decrease an alignment requirement, but GCC does not accept it on a plain uint32_t
. So the __aligned__(1)
notation is used in this answer to convey the intent of a uint32_t
with a one-byte alignment requirement, in spite of the fact there appears to be no way to specify this in GCC.