Re: question on alignment of anonymous unions inside structs

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 07/05/2024 02:06, Henrik Holst via Gcc-help wrote:
Hi,

  I understand that unions inside structs have to be aligned in case they
are referenced by a pointer or someone creates an array of them but when
the union is completely anonymous and thus none of this is possible,
shouldn't the alignment rules be relaxed?


Alignment rules are decided by the ABI for a given platform, along with the C standards. They have to be consistent, so that you can have the same declaration in different bits of code, perhaps compiled with different tools, and the layout is the same.

So the alignment values, such as on your target, "void *" pointers have an alignment of 8, are determined by the target ABI. On other platforms, such pointers might have alignment 8, 4, 2 or 1. But the rules that say unions and structs take the alignment of their most aligned field, and that padding is added to the end of structs or between fields to maintain alignment, are determined by the C standards. And these rules apply equally to anonymous unions and structs.


A compiler can't change these rules without being non-conforming. That's fine to do with explicit extensions, such as the "packed" attribute. But it takes a very strong motivation, and usually an explicit compiler flag, to break conformity for code without using extensions.

I think your best bet is a slightly smaller hammer - put __attribute__((packed, aligned(4)) on the anonymous struct, and __attribute__((aligned(64))) on the outer struct :

struct __attribute__((aligned(64))) cb3_item  {
        union {
                struct __attribute__((packed, aligned(4))) {
                        void *     ptr1;
                        void *     ptr2;
                };
                uint8_t            raw[60];
        };
        unsigned int               _avail;
};
_Static_assert(sizeof(struct cb3_item) == 64, "Check cb3_item struct");


This way you'll get your "packed" attribute only on the bit you need it, and an alignment of 4 is better than an alignment of 1. And an outer alignment of 64 ensures that the structure is cache-friendly - you wouldn't want a big array of these things to just have an 8-byte alignment.

mvh.,

David






Case in point, here I'm using pahole to show the layout and padding of the
struct:

struct cb3_item {
         union {
                 struct {
                         void *     ptr1;                 /*     0     8 */
                         void *     ptr2;                 /*     8     8 */
                 };                                       /*     0    16 */
                 uint8_t            raw[60];              /*     0    60 */
         };                                               /*     0    64 */
         /* --- cacheline 1 boundary (64 bytes) --- */
         unsigned int               _avail;               /*    64     4 */

         /* size: 72, cachelines: 2, members: 2 */
         /* padding: 4 */
         /* last cacheline: 8 bytes */
};

So my issue here is that IMHO since the union inside the struct is
anonymous there should be no need for the 4 byte padding between the union
and the _avail member. The _avail being a 32-bit integer is perfectly fine
on a 4 byte alignment so fits perfectly at position 60 which would make the
full struct 64 bytes in size and thus perfectly aligned for 64-bit
alignment.

But instead GCC (v13.2.0 in this case) aligns the union in case I would
make a pointer to it or an array of them but this cannot be done when
defined the way it is (I mean if I had done it as "union { } *p;" or
similar then I would fully understand that gcc would align it this way).

And yes I know that I can "fix" this with __attribute__((packed,aligned(1))
but that is a very broad hammer here since now one have to perform manual
alignment of each union member since alignment inside the union is ok here
but the issue is the alignment of the union as a whole.

Unless ofc if there are some other nifty solution to this that is not as
broad as using forced alignment?

/HH





[Index of Archives]     [Linux C Programming]     [Linux Kernel]     [eCos]     [Fedora Development]     [Fedora Announce]     [Autoconf]     [The DWARVES Debugging Tools]     [Yosemite Campsites]     [Yosemite News]     [Linux GCC]

  Powered by Linux