我在使用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);
}
非常感谢提前!
答案 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;
}