C# StructLayout/FieldOffset 和数组索引 [英] C# StructLayout/FieldOffset and indexing in arrays
问题描述
我在数组中正确使用 FieldOffset 时遇到了一些问题.下面的代码是一个例子,它对我来说不能正常工作:
I'm having a bit of a problem using FieldOffset correctly with arrays. The code below is an example where it doesn't work correctly for me:
[StructLayout(LayoutKind.Explicit)]
public struct IndexStruct {
[FieldOffset(0)]
public byte[] data;
[FieldOffset(0)]
public short[] idx16;
[FieldOffset(0)]
public int[] idx32;
}
例如,如果我将名为data"的数组设置为序列化的字节数组,然后尝试使用idx16"字段检索作为 short 的数据,则索引仍与字节 [] 对齐.这意味着 idx161 获取数据中的第二个字节,而不是第二个 16 位字(字节 2 和 3).如果我做反向 I 索引 shorts 而不是字节,这意味着偏移对齐是从源数据继承的.我的问题,有没有办法解决这个问题?我知道我可以通过乘以元素的大小来补偿索引值,但还有其他方法吗?
If I for example sets the array named "data" to a serialized byte array and then try to retrieve data as shorts using the "idx16" field the indexing is still aligned as a byte[]. Meaning that idx161 fetches the second byte in data, not the second 16bit word (byte 2 and 3). If I do the inverse I index shorts instead of bytes, meaning that the offset alignment is inherited from the source data. My question, is there a way to work around this? I know that I can compensate the index value by multiplying with the size of the element, but is there another way?
这里 是我在 StackOverflow 上找到的一个答案,但是在尝试该代码时发现它无法正常工作.使用以下代码在 VS 中使用单元测试进行了尝试,但没有成功:
Here is an answer I found here on StackOverflow, but when trying that code it turned out that it wasn't working properly. Tried it out using a Unit test in VS with the following code without any success:
[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);
}
非常感谢!
推荐答案
问题是(从我所见)你已经联合了数组的引用 - 所以无论哪个数组被设置最后会赢.一旦有一个数组,它就会使用索引器(而不是字节偏移量)——所以大小无关紧要.
The problem is (from what I can see) that you've unioned the references of the arrays - so whichever array gets set last will win. Once there is an array, it is using the indexer (not byte offset) - so the size doesn't matter.
正确"(或不正确,视情况而定)执行此操作的方法可能是使用不安全的代码 - 将指针指向数组 - 类似于:
The way to do this "properly" (or improperly, as the case may be) would probably be with unsafe code - taking the pointer to the array - something like:
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
}
}
当然,我不确定我是否推荐它 - 但这似乎达到了您想要的效果?
Of course, I'm not sure I recommend it - but that seems to achieve what you want?
我也想知道您是否可以完全删除 struct
并直接使用对 byte[]
的不安全访问:
I also wonder whether you can drop the struct
completely and just use unsafe access to a byte[]
directly:
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
}
}
这篇关于C# StructLayout/FieldOffset 和数组索引的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!