我试图理解显式结构布局和结构重叠,我没有看到我期望的行为。鉴于以下代码:
class Program
{
static void Main(string[] args)
{
byte[] bytes = new byte[17];
bytes[0] = 0x01; // Age is 1 //IntField1
bytes[1] = 0x00; //IntField1
bytes[2] = 0x00; //IntField1
bytes[3] = 0x00; //IntField1
bytes[4] = 0x02; //IntField2
bytes[5] = 0x00; //IntField2
bytes[6] = 0x00; //IntField2
bytes[7] = 0x00; //IntField2
bytes[8] = 0x41; //CharArray A
bytes[9] = 0x42; //CharArray B
bytes[10] = 0x43; //CharArray C
bytes[11] = 0x44; //CharArray D
bytes[12] = 0x45; //CharArray E
bytes[13] = 0x46; //CharArray F
bytes[14] = 0x00; // \0 decimal 0
bytes[15] = 0x00; // \0 decimal 0
bytes[16] = 0x01; // 1 decimal 1
Console.WriteLine(Marshal.SizeOf(typeof(TestStruct)));
TestStruct testStruct2 = (TestStruct) RawDeserialize(bytes, 0, typeof (TestStruct));
Console.WriteLine(testStruct2);
Console.ReadLine();
}
public static object RawDeserialize( byte[] rawData, int position, Type anyType )
{
int rawsize = Marshal.SizeOf( anyType );
if( rawsize > rawData.Length )
return null;
IntPtr buffer = Marshal.AllocHGlobal( rawsize );
Marshal.Copy( rawData, position, buffer, rawsize );
object retobj = Marshal.PtrToStructure( buffer, anyType );
Marshal.FreeHGlobal( buffer );
return retobj;
}
}
[StructLayout(LayoutKind.Explicit, Pack = 1)]
public struct TestStruct
{
[FieldOffset(0)]
public int IntField1;
[FieldOffset(4)]
public int IntField2;
[FieldOffset(8)]
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
public char[] CharArray;
[FieldOffset(16)]
public byte SomeByte;
[FieldOffset(8)]
public TestStruct2 SubStruct;
public override string ToString()
{
return string.Format("IntField1: {0}\nIntField2: {1}\nCharArray: {2}\nSomeByte: {3}\nSubStruct:\n{{{4}}}",
IntField1, IntField2, new string(CharArray), SomeByte, SubStruct);
}
}
[StructLayout(LayoutKind.Explicit, Pack = 1)]
public struct TestStruct2
{
[FieldOffset(0)]
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
public char[] CharArray1;
[FieldOffset(0)]
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public char[] CharArray2;
[FieldOffset(4)]
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public char[] CharArray3;
public override string ToString()
{
return string.Format("CharArray1: {0}\nCharArray2: {1}\nCharArray3: {2}",
new string(CharArray1), new string(CharArray2), new string(CharArray3));
}
}
我希望这样的结果是:
IntField1:1
IntField2:2
CharArray:ABCDEF
SomeByte:1
SubStruct:
{CharArray1:ABCDEF
CharArray2:ABCD
CharArray3:E}
但结果是:
IntField1:1
IntField2:2
CharArray:ABCD
SomeByte:1
SubStruct:
{CharArray1:ABCD
CharArray2:ABCD
CharArray3:EF}
为什么TestStruct中的CharArray长度为4?我认为它有6个字符ABCDEF,但它只包含ABCD。与TestStruct2.CharArray1相同。
答案 0 :(得分:2)
通过在CharArray之后放置TestStruct2但是在相同的偏移处,现在指向TestStruct2的CharArray2的指针覆盖了曾经是TestStruct自己的chararray的指针。
如果您注释掉或更改TestStruct2的CharArray2的长度,您将看到预期的结果。
同样注意当你把struct2放在首位时会发生什么,即:
[StructLayout(LayoutKind.Explicit, Pack = 1)]
public struct TestStruct
{
[FieldOffset(8)]
public TestStruct2 SubStruct;
[FieldOffset(0)]
public int IntField1;
[FieldOffset(4)]
public int IntField2;
[FieldOffset(8)]
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
public char[] CharArray;
[FieldOffset(16)]
public byte SomeByte;
public override string ToString()
{
return string.Format("IntField1: {0}\nIntField2: {1}\nCharArray: {2}\nSomeByte: {3}\nSubStruct:\n{{{4}}}",
IntField1, IntField2, new string(CharArray), SomeByte, SubStruct);
}
}
现在效果相反,TestStruct2的CharArray2长度为六个字符。
答案 1 :(得分:2)
char []是一个引用类型,它的大小是一个IntPtr,可以是4或8个字节 - 取决于平台(x86或x64),它的值不存储在结构中。
MarshalAs属性不会改变信息在结构中的存储方式,只会改变它的翻译方式(例如,转换为非托管代码)。
答案 2 :(得分:0)
要记住的一件事是C#中的char是一个字节的unicode字符。
虽然在保持子结构的同时仍然无法获得预期的结果。重叠的SizeConst数组似乎搞砸了。