Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unions in C#: Structure Members Do Not Seem to be Aligned

Tags:

c#

struct

unions

I have defined to following structures to emulate a C++ union (which will eventually be used for C++ Interop):

[StructLayout(LayoutKind.Sequential)]
internal struct STRUCT1
{
    public Guid guid;

    public String str1;
    public String str2;
}

[StructLayout(LayoutKind.Sequential)]
internal struct STRUCT2
{
    public Guid guid;

    public String str1;
    public String str2;

    public Int32 i1;
}

[StructLayout(LayoutKind.Explicit)]
internal struct MASTER_STRUCT_UNION
{
    [FieldOffset(0)]
    public STRUCT1 Struct1;

    [FieldOffset(0)]
    public STRUCT2 Struct2;
}

[StructLayout(LayoutKind.Sequential)]
internal struct MASTER_STRUCT
{
    public MASTER_STRUCT_UNION Union;
}

I have written the following test code which assigns a value to Struct1.guid and tests for equality to Struct2.guid:

class Class1
{
    public static void Test()
    {
        MASTER_STRUCT ms = new MASTER_STRUCT();

        bool match;
        ms.Union.Struct1.guid = new Guid(0xffeeddcc, 0xbbaa, 0x9988, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0);

        Console.WriteLine("Struct1.guid:\t\t{0}\n", ms.Union.Struct1.guid.ToString());

        Console.WriteLine("Struct2.integer:\t{0:x}", ms.Union.Struct2.i1);
        Console.WriteLine("Struct2.guid:\t\t{0}", ms.Union.Struct2.guid.ToString());


        match = ms.Union.Struct1.guid == ms.Union.Struct2.guid ? true : false;
    }
}  

Why does Struct2.guid not equal Struct1.guid and instead a segment of Struct2.guid's value seems to shift into Struct2.integer? All structure members, IMO, seem to be aligned.

like image 688
LJ VanKuiken Avatar asked Dec 24 '12 18:12

LJ VanKuiken


1 Answers

The LayoutKind.Sequential only affects the unmanaged representation of this structure. This is because the structure contains non-blittable types (namely, strings).
If only blittable types were present, LayoutKind.Sequential would control both managed and unmanaged representation (reference).

In your case, the compiler decides to put the integer before the two strings in the managed representation (you can see that if you hover over ms while debugging and unfold STRUCT2).

You can fix that by using LayoutKind.Explicit in both STRUCT1 and STRUCT2, because Explicit affects both managed and unmanaged representations for both blittable and non-blittable types.

like image 89
GSerg Avatar answered Sep 24 '22 22:09

GSerg