According to the spec [1], D structs are supposed to have the same memory layout as their C counterparts. However, writing some bindings for a C library I found the following inconsistency.
-- D code (see [2])
struct s {
union {
double d;
char[20] cs;
};
char b;
}
pragma(msg, s.b.offsetof); // Expecting 24 but getting 20
pragma(msg, s.sizeof); // Expecting 32 but getting 24
void main(){}
--
In C (using clang 7 or gcc 8.1 [3]) the offset of b is 20, but 24 when using dmd/ldc [2]. The mismatching sizeof output seems to be a result of that.
-- C code (see [3])
#include <stdio.h>
struct S {
union {
double d;
char cs[20];
};
char b;
};
int main(){
struct S s;
// Yields 24, unlike the 20 in D
printf("b at: %lu\n", (void*)&s.b-(void*)&s);
// Yields size 32, unlike the 24 in D
printf("size of s: %lu\n", sizeof(s));
}
--
[1] https://dlang.org/spec/struct.html#struct_layout
[2] https://dpaste.dzfl.pl/ff55c816a940
[3] https://www.jdoodle.com/a/Sgc
Comment #1 by kinke — 2018-12-26T16:24:27Z
This is caused by how D treats *anonymous* nested structs and unions - their fields are correctly merged into the containing aggregate (alignment etc. is fine), but the tail padding of that nested struct/union isn't applied to the offsets of the following fields (which is most likely a bug).
I.e., this ugly workaround works as expected:
struct s {
static union U { double d; char[20] cs; }
U u;
char b;
alias u this;
}
pragma(msg, s.b.offsetof); // 24
pragma(msg, s.sizeof); // 32
Comment #2 by issues.dlang — 2018-12-26T16:56:28Z
(In reply to kinke from comment #1)
> This is caused by how D treats *anonymous* nested structs and unions - their
> fields are correctly merged into the containing aggregate (alignment etc. is
> fine), but the tail padding of that nested struct/union isn't applied to the
> offsets of the following fields (which is most likely a bug).
>
> I.e., this ugly workaround works as expected:
>
> struct s {
> static union U { double d; char[20] cs; }
> U u;
> char b;
> alias u this;
> }
> pragma(msg, s.b.offsetof); // 24
> pragma(msg, s.sizeof); // 32
Thanks for the quick reply and clarification of the issue. I'll be using the workaround for now.
Comment #3 by robert.schadek — 2024-12-13T19:01:44Z