C#结构体数组的内存布局

3
在C语言中,如果我有以下结构体Data:
struct __attribute__((__packed__)) Data
{
    double x;
    int y;
};

然后创建一个名为val的该结构体的数组:

Data val[3];

val 中存储的所有值(即 val[0].x, val[0].y, val[1].x, val[1].y, val[2].xval[2].y)在内存中是连续的。

现在,在 C# 中有以下结构体:

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

然后创建一个名为val的结构体数组:

Data val[3];

我期望存储在val中的所有值都是连续存储在内存中的,但实际上它们并不是(基于我的测试结果)。具体来说,val[0].xval[0].y是连续存储的,但它们与val[1]不是连续的(而且val[1]也不与val[2]连续)。

我的问题是:在C#中,我如何创建一个特定结构的变量(它是一个数组),使其所有元素和成员都在内存中连续存储?


默认情况下,数组是连续存储的。但当使用引用类型时,只有引用是连续的。 - Eldar
2
你能展示一下那些测试吗?你所说的与数组的正常实现相矛盾(即仅对值类型数组进行连续分配)。你尝试过将fixed指针固定到&val[0]上吗? - Jcl
3
不,但是Pack=0意味着“默认填充”,而你正在查看的是最少可能的填充。在C#中,这将是Pack=1 - Jcl
@user7698505:问题已解决。非常感谢以上所有评论! - user7698505
1
我很好奇这个问题背后的用例是什么。设置 Pack=1 可能会导致问题(速度和/或稳定性)。你是出于托管/本机互操作的原因还是其他原因在这样做? - Flydog57
@Flydog57,通常是因为你的内存不足或者你必须匹配一些你无法控制的约束条件。 - greenoldman
1个回答

3

只是为了尝试一下,我做了一个非常简单的项目:使用 Pack=1 似乎可以将数据装包到最小的字节。

以下是可复现的代码(在控制台应用程序中):

[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();
                }
            }

        }
    }
}

输出:

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

在我看来,它看起来完全连续,除非我漏掉了什么


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接