Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Memory layout of C# array of struct

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.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

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?

>Solution :

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

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

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading