C#StructLayout / FieldOffset和数组索引

时间:2009-05-08 13:57:30

标签: c# arrays indexing alignment field

我在使用FieldOffset时遇到了一些问题。下面的代码是一个不适合我的例子:

[StructLayout(LayoutKind.Explicit)]
public struct IndexStruct {
    [FieldOffset(0)]
    public byte[] data;

    [FieldOffset(0)]
    public short[] idx16;

    [FieldOffset(0)]
    public int[] idx32;
}

例如,如果我将名为“data”的数组设置为序列化字节数组,然后尝试使用“idx16”字段将数据检索为short,则索引仍然作为byte []对齐。这意味着idx16 1获取数据中的第二个字节,而不是第二个16位字(字节2和3)。如果我执行逆I索引短路而不是字节,则意味着偏移对齐从源数据继承。我的问题是,有办法解决这个问题吗?我知道我可以通过乘以元素的大小来补偿索引值,但还有另一种方法吗?

Here是我在StackOverflow上找到的答案,但在尝试该代码时发现它无法正常工作。使用以下代码在VS中使用单元测试进行测试,但没有成功:

[TestMethod()]
public void SumTest() {
    float[] fArr = {2.0f, 0.5f, 0.0f, 1.0f};
    MemoryStream ms = new MemoryStream();
    for (int i = 0; i < fArr.Length; i++) {
        ms.Write(BitConverter.GetBytes(fArr[i]), 0, sizeof(float));
    }
    byte[] buff = ms.ToArray();
    double expected = 3.5f;
    double actual = Sum(buff);
    Assert.AreEqual(expected, actual);
}

非常感谢提前!

2 个答案:

答案 0 :(得分:6)

问题是(从我所看到的)你已经联合了数组的引用 - 所以最后设置的数组都会赢。一旦有数组,就会使用索引器(不是字节偏移量) - 因此大小无关紧要。

“正确”(或不正确地,视情况而定)执行此操作的方法可能是使用不安全的代码 - 将指针指向数组 - 类似于:

    IndexStruct s = new IndexStruct();
    s.data = new byte[] { 1, 0, 0, 0, 1, 1 };

    unsafe
    {
        fixed (short* data = s.idx16)
        {
            Console.WriteLine(data[0]); // should be 1 (little-endian)
            Console.WriteLine(data[1]); // should be 0
            Console.WriteLine(data[2]); // should be 257
        }
    }

当然,我不确定我是否推荐它 - 但这似乎达到了你想要的效果?

我也想知道您是否可以完全放弃struct并直接使用对byte[]的不安全访问:

    byte[] raw = new byte[] { 1, 0, 0, 0, 1, 1 };
    unsafe
    {
        fixed (byte* addr = raw)
        {
            short* s = (short*)addr;
            Console.WriteLine(s[0]); // should be 1
            Console.WriteLine(s[1]); // should be 0
            Console.WriteLine(s[2]); // should be 257
        }
    }

答案 1 :(得分:-2)

您的FieldOffset定义了每个数据元素在结构中的位置..

通过将它们全部设置为0,您告诉编译器它们都在0位。

我看到的第二件事是你正在创建一个字节,短路和整数数组。

请参阅:MSDN StructLayoutAttribute

[StructLayout(LayoutKind.Explicit)]
public struct IndexStruct {
        [FieldOffset(0)]
        public byte[16] data;

        [FieldOffset(16)]
        public short idx16;

        [FieldOffset(18)]
        public int idx32;
}