1 module nxt.aggregate_layout; 2 3 // version = show; 4 5 @safe: 6 7 void printLayout(T)() if (is(T == struct) || is(T == class) || is(T == union)) { 8 import std.stdio : writefln; 9 import std.string; 10 11 writefln("=== Memory layout of '%s'" ~ 12 " (.sizeof: %s, .alignof: %s) ===", 13 T.stringof, T.sizeof, T.alignof); 14 15 /* Prints a single line of layout information. */ 16 void printLine(size_t offset, string info) { 17 writefln("%4s: %s", offset, info); 18 } 19 20 /* Prints padding information if padding is actually 21 * observed. */ 22 void maybePrintPaddingInfo(size_t expectedOffset, 23 size_t actualOffset) { 24 if (expectedOffset < actualOffset) { 25 /* There is some padding because the actual offset 26 * is beyond the expected one. */ 27 28 const paddingSize = actualOffset - expectedOffset; 29 30 printLine(expectedOffset, 31 format("... %s-byte PADDING", 32 paddingSize)); 33 } 34 } 35 36 /* This is the expected offset of the next member if there 37 * were no padding bytes before that member. */ 38 size_t noPaddingOffset = 0; 39 40 /* Note: __traits(allMembers) is a 'string' collection of 41 * names of the members of a type. */ 42 foreach (memberName; __traits(allMembers, T)) { 43 mixin (format("alias member = %s.%s;", 44 T.stringof, memberName)); 45 46 const offset = member.offsetof; 47 maybePrintPaddingInfo(noPaddingOffset, offset); 48 49 const typeName = typeof(member).stringof; 50 printLine(offset, 51 format("%s %s", typeName, memberName)); 52 53 noPaddingOffset = offset + member.sizeof; 54 } 55 56 maybePrintPaddingInfo(noPaddingOffset, T.sizeof); 57 } 58 59 // 60 version (show) @safe unittest { 61 struct S { 62 int i; // 4 bytes 63 short s; // 2 byte 64 bool b; // 1 byte 65 } 66 static assert(S.sizeof == 8); 67 static assert(S.alignof == 4); 68 align(4) struct T { 69 align(4) S s; 70 align(1) char c; 71 } 72 static assert(T.alignof == 4); 73 /+ TODO: static assert(T.sizeof == 8); +/ 74 printLayout!(T)(); 75 } 76 77 // https://forum.dlang.org/post/jzrztbyzgxlkplslcoaj@forum.dlang.org 78 pure @safe unittest { 79 struct S { 80 int i; // 4 bytes 81 short s; // 2 byte 82 bool b; // 1 byte 83 } 84 static assert(S.sizeof == 8); 85 static assert(S.alignof == 4); 86 87 struct T { 88 union { 89 S s; 90 struct { 91 align(1): 92 ubyte[7] _ignore_me; 93 char c; 94 } 95 } 96 } 97 98 static assert(T.alignof == 4); 99 static assert(T.sizeof == 8); 100 static assert(T.c.offsetof == 7); 101 }