There has been a PR to introduce -vpadding
into dmd which warns on padding in structs.
This can actually be trivially done by core reflect.
// detect padding in aggregates
import core.reflect.reflect;
import core.reflect.transitiveVisitor;
struct PadDetctedTuple
{
string aggregateName;
ulong number_of_pad_bytes;
}
struct S
{
ubyte a; // <--- is at offset 0
ubyte b; // <--- is at offset 1
// two bytes of padding
uint d; // <--- is at offset 4
}
static assert(detectPadding(node)[0] == PadDetctedTuple("S", 2)); // yes we detected that S has 2 bytes of padding
static assert(S.init.a.offsetof == 0);
static assert(S.init.b.offsetof == 1);
static assert(S.init.d.offsetof == 4);
static immutable sc = currentScope();
static immutable node = nodeFromName("S", ReflectFlags.Members, sc);
pragma(msg, detectPadding(node));
PadDetctedTuple[] detectPadding(const Node n)
{
class PadDetectVisitor : TransitiveVisitor
{
alias visit = TransitiveVisitor.visit;
override void visit(AggregateDeclaration ad)
{
ulong lastOffset;
ulong lastSize;
ulong wastedBytes;
foreach(f;ad.fields)
{
wastedBytes += ((f.offset - lastOffset) - lastSize);
lastOffset = f.offset;
lastSize = f.type.size;
}
if (wastedBytes)
pads ~= PadDetctedTuple(ad.name, wastedBytes);
}
PadDetctedTuple[] pads = null;
}
scope padDetector = new PadDetectVisitor();
(cast()n).accept(padDetector);
return padDetector.pads;
}