5

我在正确使用 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,则索引仍对齐为字节[]。这意味着 idx16 1获取数据中的第二个字节,而不是第二个 16 位字(字节 2 和 3)。如果我做相反的我索引短裤而不是字节,这意味着偏移对齐是从源数据继承的。我的问题,有没有办法解决这个问题?我知道我可以通过乘以元素的大小来补偿索引值,但是还有其他方法吗?

是我在 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);
}

提前谢谢了!

4

2 回答 2

8

问题是(据我所知)您已经合并了数组的引用- 所以最后设置的数组将获胜。一旦有一个数组,它就会使用索引器(不是字节偏移量) - 所以大小无关紧要。

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

    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
        }
    }
于 2009-05-08T14:04:16.757 回答
-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;
}
于 2009-05-08T14:11:17.940 回答