Question: I have the following struct:

```
typedef struct __attribute__ ((__packed__))
{
    uint16_t a;
    uint32_t b;
} st_t;

```

-> the "b" member is unaligned.

When I do the following, gcc raises a warning:

```
st_t st;
uint32_t * b_p = &st.b;
*b_p = 0;

```

warning log:

```
taking address of packed member of 'struct <anonymous>' may result in an unaligned pointer value

```

But when I do the following, It does not raise any warning:

```
st_t st;
st_t * st_p = &st;
st_p->b = 0;

```

I don't understand why it does not raise a warning in the second case, since I am still accessing an unaligned member.

Answer: 
Can't provide a standard quote, so someone else will surely write a better answer, but here's a short one.

For a packed struct, from the very definition of what a "packed struct" is, compiler has to generate working machine code for any member access. Unaligned access is known and will be handled appropriately for the CPU.

Pointer to int, however, is assumed to point to a valid int, which may mean it *has to* be aligned (or there will be "bus error" or some such). Compiler generating valid unaligned access machine code for every int pointer dereference would be quite inefficient on CPUs where it matters, so compiler basically *has to* make this assumption.

So, if compiler notices a pointer to unaligned address, it rightfully warns, because it is illegal operation on some CPUs, and it may be slower than aligned access even if it is legal. It won't warn for packed struct, because programmer explocitly says "this is unaligned, deal with it" by making the struct packed.
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](https://stackoverflow.com/a/66389167/298225). 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.