C#StructLayout / FieldOffset和数组索引

我在使用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索引短路而不是字节,这意味着偏移对齐是从源数据inheritance的。 我的问题是,有办法解决这个问题吗? 我知道我可以通过乘以元素的大小来补偿索引值,但还有另一种方法吗?

这是我在StackOverflow上找到的答案,但是当尝试该代码时,结果certificate它无法正常工作。 使用以下代码在VS中使用unit testing尝试使用它,但没有成功:

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

提前谢谢了!

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

“正确”(或不正确地,视情况而定)这样做的方法可能是使用不安全的代码 – 将指针指向数组 – 类似于:

  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 } } 

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; }