www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Struct alignment vs alignment of fields

reply "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> writes:
(Original discussion: 
http://forum.dlang.org/thread/fckwpddiwxonabqaflqt forum.dlang.org#post-pskjgieddhpntzaokohj:40forum.dlang.org)

     align(1) struct A
     {
     align(1):
         int qtim;
         int bid;
         int ofr;
         int bidsiz;
         int ofrsiz;
         short mode;
         char[1] ex;
         char[4] mmid;
     }

     align(1) struct B
     {
         int qtim;
         int bid;
         int ofr;
         int bidsiz;
         int ofrsiz;
         short mode;
         char[1] ex;
         char[4] mmid;
     }

I would expect `B` to have a gap between `ex` and `mmid`. AFAIK 
the outer `align(1)` only applies to the struct in its entirety, 
not to the individual fields. However for both DMD git and LDC 
0.14.0-alpha1 (based on DMD 2.065), `A` and `B` have the same 
size.

After some thinking, I believe this is because arrays inherit the 
alignment of their element types. Is this correct? If yes, where 
is this documented? I had expected `char[4]` to be aligned at a 
4-byte boundary.
Aug 07 2014
next sibling parent reply "Era Scarecrow" <rtcvb32 yahoo.com> writes:
On Thursday, 7 August 2014 at 17:22:15 UTC, Marc Sch├╝tz wrote:
 (Original discussion: 
 http://forum.dlang.org/thread/fckwpddiwxonabqaflqt forum.dlang.org#post-pskjgieddhpntzaokohj:40forum.dlang.org)
 I would expect `B` to have a gap between `ex` and `mmid`. AFAIK 
 the outer `align(1)` only applies to the struct in its 
 entirety, not to the individual fields. However for both DMD 
 git and LDC 0.14.0-alpha1 (based on DMD 2.065), `A` and `B` 
 have the same size.
 After some thinking, I believe this is because arrays inherit 
 the alignment of their element types. Is this correct? If yes, 
 where is this documented? I had expected `char[4]` to be 
 aligned at a 4-byte boundary.
I'm not sure about all the latest compiler changes, but let's try and answer some of this. TDPL pg. 268-269 explains this (although could be out of date with recent changes). I'll copy what's relevant.. 7.1.11.1 The align Attribute If you want to override the compiler's choice of alignment, which influences the padding inserted. You could use an align modifier... etc.. class A { char a; align(1) int b; char c; } With the specification above the fields of A are laid out without gaps between them. You may use align with an entire class definition: align(1) struct S { char a; int b; char c } ... Align is not suppose to be used with pointers and references... Back to the question. Most fields will be aligned on 4-byte boundaries, or 8-byte depending on if it's 32/64 bit. This is mostly for performance reasons, but also with addresses it may affect the GC. Overriding the compiler is mostly going to be more useful when working against C/C++ structures where they are also forcibly aligned for space. So assuming we have the above struct. S[2] s; It's probably going to be aligned on 4's for the first one; But it doesn't have to be. But the others? I'm not so sure... The inner alignment and padding is 4 per, so if the struct S has a size of 12, then it's still going to be aligned by 4's by default... i think? Maybe the alignment has to do if it's inserted into another object. On the stack it probably ignores the alignment attribute... struct B { char a; S s; //infers align(1) by it's definition? } Well regardless, unless you're overriding both, you're probably going to get some form of alignments of 4, be it for arrays or for speed... I hope this isn't confusing.
Aug 07 2014
parent "Era Scarecrow" <rtcvb32 yahoo.com> writes:
Still watching this, but the Dconf 2014 bare metal presentation 
gets into it a bit...

  http://youtu.be/qErXPomAWYI?t=37m20s
Aug 07 2014
prev sibling next sibling parent reply "ketmar" <ketmar ketmar.no-ip.org> writes:
yeah, chars (and bytes, and so on) are not aligned. i.e.

align(1) struct B {
   int qtim;
   int bid;
   int ofr;
   int bidsiz;
   int ofrsiz;
   short mode;
   char ex;
   byte mmid;
   char z;
}

has sizeof == 25. not sure if specs mentions this, but they 
should.
Aug 08 2014
parent "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> writes:
On Friday, 8 August 2014 at 18:20:41 UTC, ketmar wrote:
 yeah, chars (and bytes, and so on) are not aligned. i.e.

 align(1) struct B {
   int qtim;
   int bid;
   int ofr;
   int bidsiz;
   int ofrsiz;
   short mode;
   char ex;
   byte mmid;
   char z;
 }

 has sizeof == 25. not sure if specs mentions this, but they 
 should.
It's not surprising that `char` and `byte` behave like this, because `byte.alignof == 1`. But it's not obvious that this also applies to arrays of them. I had expected them to be treated as opaque objects of a certain size, and therefore have an alignment that corresponds to their size. pragma(msg, byte.alignof); pragma(msg, (byte[1]).alignof); pragma(msg, (byte[2]).alignof); pragma(msg, (byte[3]).alignof); pragma(msg, (byte[4]).alignof); pragma(msg, (byte[5]).alignof); pragma(msg, (byte[6]).alignof); struct S { byte a; byte b; byte c; byte d; } struct T { byte a; short b; int c; } pragma(msg, S.alignof); pragma(msg, T.alignof); This outputs "1" for all types except `T`, which has 4. So this even applies to structs, not only arrays. Which may make sense, because each element will always be accessed with correct alignment. However, accessing the aggregate as a whole might result in unaligned reads/writes.
Aug 09 2014
prev sibling parent "ketmar" <ketmar ketmar.no-ip.org> writes:
p.s. seems that aligning works only on ints. i.e. on types which 
has sizeof >= default platform align.
Aug 08 2014