[cfe-dev] 'struct' member alignment query

Richard Smith via cfe-dev cfe-dev at lists.llvm.org
Thu Feb 9 22:09:09 PST 2017


On 9 Feb 2017 11:54 am, "Martin J. O'Riordan" <martin.oriordan at movidius.com>
wrote:

Hi Richard,



How does ‘packed’ work in this context?  I thought ‘packed’ would cause the
whole aggregate to eliminate padding, rather than just changing the
alignment requirements of a single member.

What packed actually does is to reduce the minimum alignment to 1. When
applied to a struct, it is effectively applied to all fields.

What I want is that the outer aggregate is aligned in the normal way
according the maximum alignment requirements of its members.  However, I
want to also have a member which itself is an aggregate with its usual
internal padding retained, but changed its alignment constraint
(essentially lying) within the context of the enclosing aggregate.



Would ‘packed’ not just unilaterally remove the padding?



For example (assuming char is 1-byte and int is 4, and natural alignment):



struct Inner {

  char c;

  int  i;

};

Inner x;



I can reasonably assume on a naturally aligned system that the following
would hold true (undefined ISO behaviour ignored regarding address
arithmetic - assume a simple conventional 32-bit Von Neumann address space):



sizeof(Inner) == 8

((unsigned)&x & 7) == 0

((unsigned)&x.i - (unsigned)&x.c) == 4

offsetof(Outer, c) == 0

offsetof(Outer, i) == 4



Now what I want to do is:



struct Outer {

  char aa;

  int  bb;

  char cc;

  [magic attribute] Inner xx;

  char dd;

  int  ee;

};

Outer y;



Such that:



sizeof(Outer) == 24

((unsigned)&y & 7) == 0

((unsigned)&y.xx.i - (unsigned)&y.xx.c) == 4

((unsigned)&y.xx.i - (unsigned)&y) == 13

offsetof(Inner, bb) == 4

offsetof(Inner, cc) == 8

offsetof(Inner, xx) == 9

offsetof(Inner, dd) == 17

offsetof(Inner, ee) == 20



so padding is still present within the layout of ‘xx’, and also as normal
for the member alignment of ‘aa’, ‘bb’, ‘cc’, ‘dd’ and ‘ee’ within ‘Outer’,
but not for ‘xx’.



This is useful when overlaying structures on registers in a memory-mapped
device which can have weird arrangements, and avoid the need for dirty
little macro arithmetic tricks which are sadly very common in embedded
systems device driver code.



So forgive me if I am misunderstanding ‘packed’ (and I probably am), but
will this not cause the members of ‘Inner’ as a member of ‘Outer’ to become
packed ((unsigned)&i == (unsigned)&c + 1), or does it simply loosen the
alignment constraint within the members of ‘Outer’ to achieve what I
intend?  I usually interpret ‘packed’ as all-or-nothing.  So if I
replace ‘[magic
attribute]’ with ‘__attribute__((packed))’, this will achieve the effect I
require?  What if I want to force alignment of ‘xx’ to 2-bytes instead of 1?



The only reasonably portable way I know of doing this kind of thing, is to
always pack structures, and to explicitly provide the dummy padding bytes
(including bitfield alignment magic such as ‘int:0;’), but while these are
mostly-portable, they are not absolute in the context of a specific
implementation - which is where ‘__attribute__((aligned(x)))’ is necessary.



In any case, the incongruity of using ‘aligned’ in a ‘typedef’ versus
explicitly on the member is quite unintuitive, though I fully understand
the need for CLang to maintain compatibility with GCC in this regard.



Thanks,



            MartinO



*From:* metafoo at gmail.com [mailto:metafoo at gmail.com] *On Behalf Of *Richard
Smith
*Sent:* 09 February 2017 18:03

*To:* Martin J. O'Riordan <Martin.ORiordan at movidius.com>
*Cc:* Clang Dev <cfe-dev at lists.llvm.org>; Tim Northover <
t.p.northover at gmail.com>

*Subject:* Re: [cfe-dev] 'struct' member alignment query



The "right" way to get this effect is to use __attribute__((packed)) on the
field.



On 9 Feb 2017 9:33 am, "Martin J. O'Riordan via cfe-dev" <
cfe-dev at lists.llvm.org> wrote:

Wow!  Thanks for the response, that worked perfectly.

I never would have expected that the indirect 'typedef' approach would
behave any differently to the more direct annotation!  I feel that this is
probably an unintended GCC behaviour/bug, though CLang is 100% right to
maintain compatibility with GCC.

But it solved my problem, thanks very much,

        MartinO


-----Original Message-----
From: Tim Northover [mailto:t.p.northover at gmail.com]
Sent: 09 February 2017 15:08
To: Martin J. O'Riordan <Martin.ORiordan at movidius.com>
Cc: cfe-dev <cfe-dev at lists.llvm.org>
Subject: Re: [cfe-dev] 'struct' member alignment query

On 9 February 2017 at 02:56, Martin J. O'Riordan via cfe-dev <
cfe-dev at lists.llvm.org> wrote:
> Is this expected behaviour in 'clang', and if so, is there another way
> I can coerce the 'struct' member 'alignCheck2' onto another less
> constrained alignment boundary?

It's expected, but I think only because of GCC compatibility because it's
really not obvious behaviour. The workaround, which still mystifies me, is
to go via a typedef:

typedef AlignCheck_t __attribute__((aligned(1))) UnAlignCheck_t;

then you can put that in the struct and it'll be laid out without any
padding.

Tim.

_______________________________________________
cfe-dev mailing list
cfe-dev at lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20170209/0456a309/attachment.html>


More information about the cfe-dev mailing list