3

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?

6
  • Arrays are stored contigous by default. Except when a reference type is used. In that case only references are contigous. Commented Jan 7, 2022 at 17:27
  • 2
    Can you show us those tests? What you say contradicts the normal implementations of arrays (which is having them contiguous for value type-only arrays). Have you tried pinning a fixed pointer to &val[0]? Commented Jan 7, 2022 at 17:30
  • 3
    @user7698505 no, but Pack=0 means "default padding", and what you are looking at is packing at the least possible. That'd be Pack=1 in C# I believe Commented Jan 7, 2022 at 17:48
  • @user7698505: it solved the issue. Thank you very much for all the comments above! Commented Jan 7, 2022 at 17:50
  • 1
    I'm curious what the use case is behind this question. Setting Pack=1 can cause issues (speed and/or stability). Are you doing the for managed/native interop reasons, or something else? Commented Jan 7, 2022 at 19:15

1 Answer 1

3

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

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.