Are unpacked struct in packed struct automatically packed?
Asked Answered
Z

3

8

Are unpacked struct in packed struct automatically packed by GCC?

In other words, do __packed__ attribute automatically propagates to nested structures?

That is to say:

struct unpackedStruct{
    int16_t field1;
    int32_t field2;
    // etc...
}

struct packedStruct{
    int16_t field1;
    struct unpackedStruct struct1; // <-- Is this struct packed?
    // etc...
} __attribute__((__packed__));
Zeke answered 26/2, 2021 at 15:52 Comment(3)
It better not be - otherwise passing that member to any other code expecting an ordinary unpackedStruct will fail miserably. Anyway, you could test it.Hyperaemia
@NateEldredge Also, doing direct assignment from one to another would not work.Unequaled
This should be trivial to check using the compiler.Carner
F
11

No, the inner structure is not packed. In this Godbolt example, we can see that struct foo is not packed inside struct bar, which has the packed attribute; the struct bar object created contains three bytes of padding (visible as .zero 3) inside its struct foo member, between the struct foo members c and i.

Current documentation for GCC 10.2 explicitly says the internal layout of a member of a packed structure is not packed (because of the attribute on the outer structure; it could be packed due to its own definition, of course).

(In older documentation that said that applying packed to a structure is equivalent to applying it to its members, it meant the effect of applying packed to the “variable” that is the member, described in the documentation for variable attributes. When packed is applied to a structure member, it causes the member’s alignment requirement to be one byte. That is, it eliminates padding between previous members and that member, because no padding is needed to make it aligned. It does not alter the representation of the member itself. If that member is an unpacked structure, it remains, internally, an unpacked structure.)

Firebrick answered 26/2, 2021 at 16:9 Comment(0)
H
2

In practice it does not: see https://godbolt.org/z/4YMaz8. Note the .zero 2 of padding between the two members of the unpackedStruct member.

This situation is explicitly mentioned in the manual, with an example almost identical to yours:

In the following example struct my_packed_struct’s members are packed closely together, but the internal layout of its s member is not packed—to do that, struct my_unpacked_struct needs to be packed too.

struct my_unpacked_struct
 {
    char c;
    int i;
 };

struct __attribute__ ((__packed__)) my_packed_struct
  {
     char c;
     int  i;
     struct my_unpacked_struct s;
  };

The basic idea is that every object of a given type should have the same layout, so that code operating on that type will work on every object of that type. So packed has to apply to a type, and you can't have some objects of that type packed and others not.

Hyperaemia answered 26/2, 2021 at 16:4 Comment(4)
I think that bar and foo code has to break anyway, because &p.struct1 may not be aligned as a struct my_unpacked_struct should be. Clang produces “error: taking address of packed member 's' of class or structure 'my_packed_struct' may result in an unaligned pointer value [-Werror,-Waddress-of-packed-member]” while GCC 10.2 is silent.Firebrick
Well, let's say it will break worse - on a platform without strict alignment requirements, it would be likely to work. Or you could imagine applying __attribute__((aligned(1))) to struct unpackedStruct.Hyperaemia
@EricPostpischil: But I'll take that out anyway.Hyperaemia
I would leave it in but mention the alignment issue separately. If a struct foo member were truly packed, it could not be used as a struct foo at all. But since it is not packed, just misaligned, there are effectively two types, a struct foo and a struct foo __attribute__((__aligned__(1))). You can memcpy one to the other.Firebrick
T
0

No - packing is not recursive so every member needs to be packed itself.

Toliver answered 26/2, 2021 at 16:17 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.