Home > Back-end >  Memory layout of C# array of struct
Memory layout of C# array of struct

Time:01-08

In C, if I have the following struct Data:

struct __attribute__((__packed__)) Data
{
    double x;
    int y;
};

And then create an array named val of this struct:

Data val[3];

All values stored in val (i.e. val[0].x, val[0].y, val[1].x, val[1].y, val[2].x and val[2].y are contiguous in memory.

Now, when having the following struct in C#:

[StructLayout(LayoutKind.Sequential, Pack=0)]
struct Data
{
    public double x;
    public int y;
}

And then create an array named val of this struct:

Data val[3];

I would expect that all values stored in val are contiguous in memory, which they are not (based on the tests that I have conducted). In details, val[0].x and val[0].y are both contiguous, but they are not contiguous with val[1] (which, in turn, is not contiguous with val[2]).

My question is: in C#, how can I create a variable (that is an array) of a certain struct that all its elements and members are contiguous in memory?

CodePudding user response:

Just to try it, I made a very simple project: using Pack=1 seems to pack perfectly fine to the smallest byte.

Reproducing code (on a console app):

[StructLayout(LayoutKind.Sequential, Pack=1)]
struct Data
{
    public double x;
    public int y;
}

class Program {
    static void Main()
    {
        Data[] val = new Data[3] {
            new Data { x = 0, y = 0 },
            new Data { x = 1, y = 1 },
            new Data { x = 2, y = 2 },
        };

        for(var i = 0; i < 3; i  )
        {
            Console.WriteLine("data["   i   "].x = "   BitConverter.ToString(BitConverter.GetBytes(val[i].x)));
            Console.WriteLine("data["   i   "].y = "   BitConverter.ToString(BitConverter.GetBytes(val[i].y)));
        }       

        unsafe {
            fixed (Data *p = &val[0])
            {
                byte *c = (byte *)p;
                for(var j = 0; j < 3; j  )
                {
                    for(var i = 0; i < Marshal.SizeOf<double>(); i  , c  )
                    {
                        if(i!=0) Console.Write("-");
                        Console.Write("{0:X2}", *c);
                    }
                    Console.WriteLine();
                    for(var i = 0; i < Marshal.SizeOf<int>(); i  , c  )
                    {
                        if(i!=0) Console.Write("-");
                        Console.Write("{0:X2}", *c);
                    }
                    Console.WriteLine();
                }
            }

        }
    }
}

Output:

data[0].x = 00-00-00-00-00-00-00-00
data[0].y = 00-00-00-00
data[1].x = 00-00-00-00-00-00-F0-3F
data[1].y = 01-00-00-00
data[2].x = 00-00-00-00-00-00-00-40
data[2].y = 02-00-00-00
00-00-00-00-00-00-00-00
00-00-00-00
00-00-00-00-00-00-F0-3F
01-00-00-00
00-00-00-00-00-00-00-40
02-00-00-00

Which looks perfectly continuous to me, unless I'm missing something

  •  Tags:  
  • Related