在C#中使用以下两个方法进行序列化和反序列化中,如果结构体AnyStruct内容采用[StructLayout(LayoutKind.Sequential)]则会造成在结构体中添加成员变量后由于内存没有对齐,使得原来的变量值受到影响。
private byte[] Serialize(object obj)
{int rawSize = Marshal.SizeOf(obj);
IntPtr buffer = Marshal.AllocHGlobal(rawSize);
Marshal.StructureToPtr(obj, buffer, false);
byte[] rawDatas = new byte[rawSize];
Marshal.Copy(buffer, rawDatas, 0, rawSize);
Marshal.FreeHGlobal(buffer);
return rawDatas;
}
private AnyStruct Deserialize(byte[] rawDatas)
{Type anyType = typeof(AnyStruct);
int rawSize = Marshal.SizeOf(anyType);
if (rawSize > rawDatas.Length) return new AnyStruct();
IntPtr buffer = Marshal.AllocHGlobal(rawSize);
Marshal.Copy(rawDatas, 0, buffer, rawSize);
object retobj = Marshal.PtrToStructure(buffer, anyType);
Marshal.FreeHGlobal(buffer);
return (AnyStruct)retobj;
}
如下所示,当采用[StructLayout(LayoutKind.Explicit)]标记每个成员变量在内存中的存放位置时则在Y3后添加字节数等于或者小于float的变量后不会影响原来的值,但当添加一个double类型的参数后还是会影响原来的成员变量的值。
[StructLayout(LayoutKind.Explicit)]
public struct AnyStruct
{
[FieldOffset(0)]
public int ID;
[FieldOffset(8)]
public ushort Type;
[FieldOffset(16)]
public float X1;
[FieldOffset(24)]
public float Y1;
[FieldOffset(32)]
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)]
public byte[] data;
}
当把以上结构体中的任意一个成员变量改为double类型,则后续随意加什么类型的变量都不会对之前的成员变量造成影响。
总结:是否采用[StructLayout(LayoutKind.Explicit)]后结构体中如果最大为float,也就是4byte,虽然规定之前的每个成员变量的位置为相隔8byte,但是剩余的128byte还是安装最大成员变量float的4byte进行排列,导致添加一个double的8byte变量时内存对齐错误,而当之前的成员变量里含有一个double的8byte时,后续的128byte都是按照相隔8byte来排列,也就不会出错,望高手解答!