Thread overview | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
October 16, 2020 Packing of Struct Fields | ||||
---|---|---|---|---|
| ||||
Why is `T.sizeof` 12 instead of 8 when `U.sizeof` is 8 in the following example? struct S { int i; bool b; } struct T { S s; char c; } struct U { int i; bool b; char c; } ? |
October 16, 2020 Re: Packing of Struct Fields | ||||
---|---|---|---|---|
| ||||
Posted in reply to Per Nordlöw | On 16.10.20 22:32, Per Nordlöw wrote:
> Why is `T.sizeof` 12 instead of 8 when `U.sizeof` is 8 in the following example?
>
> struct S
> {
> int i;
> bool b;
> }
>
> struct T
> {
> S s;
> char c;
> }
>
> struct U
> {
> int i;
> bool b;
> char c;
> }
>
> ?
S.sizeof: 4 bytes for the int + 1 byte for the bool + 3 bytes padding so that the int is aligned = 8 bytes.
T.sizeof: 8 bytes for the S + 1 byte for the char + 3 bytes padding so that the S is aligned = 12 bytes.
U.sizeof: 4 bytes for the int + 1 byte for the bool + 1 byte for the char + 2 bytes padding so that the int is aligned = 8 bytes.
|
October 16, 2020 Re: Packing of Struct Fields | ||||
---|---|---|---|---|
| ||||
Posted in reply to Per Nordlöw | On 10/16/20 1:32 PM, Per Nordlöw wrote: > Why is `T.sizeof` 12 instead of 8 when `U.sizeof` is 8 in the following example? > > struct S > { > int i; > bool b; > } > > struct T > { > S s; > char c; > } > > struct U > { > int i; > bool b; > char c; > } > > ? I have a function that dumps member layout of structs, which someone may find useful: http://ddili.org/ders/d.en/memory.html#ix_memory..offsetof It prints the following for these types: === Memory layout of 'S' (.sizeof: 8, .alignof: 4) === 0: int i 4: bool b 5: ... 3-byte PADDING === Memory layout of 'T' (.sizeof: 12, .alignof: 4) === 0: S s 8: char c 9: ... 3-byte PADDING === Memory layout of 'U' (.sizeof: 8, .alignof: 4) === 0: int i 4: bool b 5: char c 6: ... 2-byte PADDING Copied here: struct S { int i; bool b; } struct T { S s; char c; } struct U { int i; bool b; char c; } void printObjectLayout(T)() if (is (T == struct) || is (T == union)) { import std.stdio; import std.string; writefln("=== Memory layout of '%s'" ~ " (.sizeof: %s, .alignof: %s) ===", T.stringof, T.sizeof, T.alignof); /* Prints a single line of layout information. */ void printLine(size_t offset, string info) { writefln("%4s: %s", offset, info); } /* Prints padding information if padding is actually * observed. */ void maybePrintPaddingInfo(size_t expectedOffset, size_t actualOffset) { if (expectedOffset < actualOffset) { /* There is some padding because the actual offset * is beyond the expected one. */ const paddingSize = actualOffset - expectedOffset; printLine(expectedOffset, format("... %s-byte PADDING", paddingSize)); } } /* This is the expected offset of the next member if there * were no padding bytes before that member. */ size_t noPaddingOffset = 0; /* Note: __traits(allMembers) is a 'string' collection of * names of the members of a type. */ foreach (memberName; __traits(allMembers, T)) { mixin (format("alias member = %s.%s;", T.stringof, memberName)); const offset = member.offsetof; maybePrintPaddingInfo(noPaddingOffset, offset); const typeName = typeof(member).stringof; printLine(offset, format("%s %s", typeName, memberName)); noPaddingOffset = offset + member.sizeof; } maybePrintPaddingInfo(noPaddingOffset, T.sizeof); } void main() { printObjectLayout!S(); printObjectLayout!T(); printObjectLayout!U(); } Ali |
October 16, 2020 Re: Packing of Struct Fields | ||||
---|---|---|---|---|
| ||||
Posted in reply to ag0aep6g | On 10/16/20 4:44 PM, ag0aep6g wrote: > On 16.10.20 22:32, Per Nordlöw wrote: >> Why is `T.sizeof` 12 instead of 8 when `U.sizeof` is 8 in the following example? >> >> struct S >> { >> int i; >> bool b; >> } >> >> struct T >> { >> S s; >> char c; >> } >> >> struct U >> { >> int i; >> bool b; >> char c; >> } >> >> ? > > S.sizeof: 4 bytes for the int + 1 byte for the bool + 3 bytes padding so that the int is aligned = 8 bytes. > > T.sizeof: 8 bytes for the S + 1 byte for the char + 3 bytes padding so that the S is aligned = 12 bytes. > > U.sizeof: 4 bytes for the int + 1 byte for the bool + 1 byte for the char + 2 bytes padding so that the int is aligned = 8 bytes. To further explain this -- the padding is added so things like pointer arithmetic on an array work. For example, if you have a T* t, and you say t += 1, you want it to go to the next T, not to a misaligned spot. You can also override this with align keyword. But I don't recommended this unless you know what you are doing. Misaligned reads/writes are different on different architectures, but even if they work and don't crash your program, they are going to be slower. https://dlang.org/spec/attribute.html#align -Steve |
October 17, 2020 Re: Packing of Struct Fields | ||||
---|---|---|---|---|
| ||||
Posted in reply to Steven Schveighoffer | On Friday, 16 October 2020 at 21:26:12 UTC, Steven Schveighoffer wrote:
> To further explain this -- the padding is added so things like pointer arithmetic on an array work.
In my code sample above one can only access the first element anyhow so I don't understand why this restriction is imposed here.
struct S
{
int i;
bool b;
}
struct T
{
S s; // reinterpreting this as an array can only access this first element anyway
char c; // so why can't this be aligned directly after `s` without any padding?
}
|
October 17, 2020 Re: Packing of Struct Fields | ||||
---|---|---|---|---|
| ||||
Posted in reply to Per Nordlöw | On Saturday, 17 October 2020 at 12:35:37 UTC, Per Nordlöw wrote:
> On Friday, 16 October 2020 at 21:26:12 UTC, Steven Schveighoffer wrote:
>> To further explain this -- the padding is added so things like pointer arithmetic on an array work.
>
> In my code sample above one can only access the first element anyhow so I don't understand why this restriction is imposed here.
>
> struct S
> {
> int i;
> bool b;
> }
>
> struct T
> {
> S s; // reinterpreting this as an array can only access this first element anyway
> char c; // so why can't this be aligned directly after `s` without any padding?
> }
So AFAICT the key question becomes:
Can `align`s be inserted in S or/and T so that T is packed to 8 bytes but still aligned to 8 bytes? I don't see why this shouldn't be the default behaviour...
|
October 17, 2020 Re: Packing of Struct Fields | ||||
---|---|---|---|---|
| ||||
Posted in reply to Per Nordlöw | On Saturday, 17 October 2020 at 12:44:44 UTC, Per Nordlöw wrote: > Can `align`s be inserted in S or/and T so that T is packed to 8 bytes but still aligned to 8 bytes? Yes. Put an align on the OUTSIDE of the struct you are nesting, then put one INSIDE the struct you want the contents packed. > I don't see why this shouldn't be the default behaviour... It is generally slower. |
October 17, 2020 Re: Packing of Struct Fields | ||||
---|---|---|---|---|
| ||||
Posted in reply to Per Nordlöw | On Saturday, 17 October 2020 at 12:44:44 UTC, Per Nordlöw wrote:
> Can `align`s be inserted in S or/and T so that T is packed to 8 bytes but still aligned to 8 bytes? I don't see why this shouldn't be the default behaviour...
I though this would do the trick but not...
struct S
{
int i; // 4 bytes
short s; // 2 byte
bool b; // 1 byte
}
static assert(S.sizeof == 8);
static assert(S.alignof == 4);
align(4) struct T
{
align(4) S s;
align(1) char c;
}
static assert(T.alignof == 4);
// TODO: static assert(T.sizeof == 8);
T.sizeof is still 12 bytes, I want it to be 8.
|
October 17, 2020 Re: Packing of Struct Fields | ||||
---|---|---|---|---|
| ||||
Posted in reply to Per Nordlöw | On 17.10.20 14:35, Per Nordlöw wrote:
> struct S
> {
> int i;
> bool b;
> }
>
> struct T
> {
> S s; // reinterpreting this as an array can only access this first element anyway
> char c; // so why can't this be aligned directly after `s` without any padding?
> }
>
c does come directly after s. The padding between b and c is part of s. If you don't want that padding, you can use `align(1)` to define S without padding. But then 75% of the ints in an S[] will be misaligned.
|
October 17, 2020 Re: Packing of Struct Fields | ||||
---|---|---|---|---|
| ||||
Posted in reply to ag0aep6g | On Saturday, 17 October 2020 at 12:51:21 UTC, ag0aep6g wrote:
> c does come directly after s. The padding between b and c is part of s. If you don't want that padding, you can use `align(1)` to define S without padding. But then 75% of the ints in an S[] will be misaligned.
I understand that. I don't want the alignment of `S` to change. I want the padding after `s` in `T` to be avoided and have `c` start at byte-offset 7. I don't see why this padding is needed in the case where only a single (1-element array of) `S` is stored as a field inside another aggregate.
Ali's code prints:
=== Memory layout of 'T' (.sizeof: 12, .alignof: 4) ===
0: S s
8: char c
9: ... 3-byte PADDING
|
Copyright © 1999-2021 by the D Language Foundation