D issues are now tracked on GitHub. This Bugzilla instance remains as a read-only archive.
Issue 19516 - Alignment of members & size of structs inconsistent with C
Summary: Alignment of members & size of structs inconsistent with C
Status: NEW
Alias: None
Product: D
Classification: Unclassified
Component: dmd (show other issues)
Version: D2
Hardware: x86_64 All
: P3 normal
Assignee: No Owner
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2018-12-26 15:36 UTC by dbohlender
Modified: 2024-12-13 19:01 UTC (History)
1 user (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this issue.
Description dbohlender 2018-12-26 15:36:46 UTC
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 kinke 2018-12-26 16:24:27 UTC
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 dbohlender 2018-12-26 16:56:28 UTC
(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 dlangBugzillaToGithub 2024-12-13 19:01:44 UTC
THIS ISSUE HAS BEEN MOVED TO GITHUB

https://github.com/dlang/dmd/issues/19520

DO NOT COMMENT HERE ANYMORE, NOBODY WILL SEE IT, THIS ISSUE HAS BEEN MOVED TO GITHUB