需求场景
环境说明:VS 2013 Pro, .net framework 4.5
需要将接收到的数据包按照帧格式进行解析,获得具有单独意义的字节信息
需要将已有的字节信息按照帧格式组成帧,以用于后续环节
如果采用按字节位置进行解析的方式,需要计算每个字段的起始位置,处理过程繁琐,且当帧格式发生变化的时候,代码调整比较麻烦
尝试通过内存操作,直接将字节数组的内存单元按照结构体的方式来处理,操作较为简单,且修改方便
命名空间
c#中采用内存方式转换字节数组与结构体需要使用一个单独的命名空间
using System.Runtime.InteropServices;
结构体定义
需要预先定义好与字节数组长度相等的结构体,用于容纳字节数组中的字节信息
[StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
struct DataStruct
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public byte[] head;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public byte[] frameCount;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public byte[] len;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public byte[] func;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public byte[] data;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public byte[] check;
}
关于结构体的内存对齐,我们知道,结构体的内存大小通常为对齐长度的整数倍。这会造成结构体占用内存大小与其内容大小不一致
这里,由于我们需要将字节数组的内存直接赋给结构体,结构体的大小必须与字节数组完全相等,所以需要取消结构体的内存对齐
代码中的 Pack = 1 即为设置对齐长度为1,即结构体内存长度为1 的整数倍
字节数组转结构体
private object BytesToDataStruct(byte[] bytes, Type type)
{
//DataStruct data = new DataStruct();
int size = Marshal.SizeOf(type);
if (size > bytes.Length)
{
return null;
}
IntPtr structPtr = Marshal.AllocHGlobal(size);
Marshal.Copy(bytes, 0, structPtr, size);
object obj = Marshal.PtrToStructure(structPtr, type);
Marshal.FreeHGlobal(structPtr);
return obj;
}
代码说明:
- 首先,获得结构体类型需要的内存长度 size,判断能否转换
- 开辟一段长度为 size 的内存空间
- 将字节数组内容拷贝至内存空间中
- 将该内存空间赋给对象obj
- 释放内存空间指针,返回对象obj
- 接下来可将obj转换为任意类型的struct
使用方式为
DataStruct frame = (DataStruct)BytesToDataStruct(bytes, typeof(DataStruct));
结构体转字节数组
private byte[] StructToBytes(object anyStruct)
{
int size = Marshal.SizeOf(anyStruct);
IntPtr bytesPtr = Marshal.AllocHGlobal(size);
Marshal.StructureToPtr(anyStruct, bytesPtr, false);
byte[] bytes = new byte[size];
Marshal.Copy(bytesPtr, bytes, 0, size);
Marshal.FreeHGlobal(bytesPtr);
return bytes;
}
代码说明:
- 获得结构体的大小 size
- 开辟一段长度为 size 的内存空间
- 将结构体的内存空间中的内容赋给新开辟的内存空间
- 定义一个大小为 size 的字节数组
- 将内存空间的内容拷贝至字节数组中
- 释放内存空间指针,返回字节数组
使用方式为
byte[] bytes = StructToBytes(frame)