从字节数组读取C#中的C / C ++数据结构
时间:2020-03-05 18:37:52 来源:igfitidea点击:
从数据来自C / C ++结构的byte []数组填充Cstruct的最佳方法是什么? C结构看起来像这样(我的C非常生锈):
typedef OldStuff { CHAR Name[8]; UInt32 User; CHAR Location[8]; UInt32 TimeStamp; UInt32 Sequence; CHAR Tracking[16]; CHAR Filler[12]; }
并会填充如下内容:
[StructLayout(LayoutKind.Explicit, Size = 56, Pack = 1)] public struct NewStuff { [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 8)] [FieldOffset(0)] public string Name; [MarshalAs(UnmanagedType.U4)] [FieldOffset(8)] public uint User; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 8)] [FieldOffset(12)] public string Location; [MarshalAs(UnmanagedType.U4)] [FieldOffset(20)] public uint TimeStamp; [MarshalAs(UnmanagedType.U4)] [FieldOffset(24)] public uint Sequence; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)] [FieldOffset(28)] public string Tracking; }
如果将OldStuff作为byte []数组传递,将OldStuff复制到NewStuff的最佳方法是什么?
我目前正在执行以下操作,但感觉有些笨拙。
GCHandle handle; NewStuff MyStuff; int BufferSize = Marshal.SizeOf(typeof(NewStuff)); byte[] buff = new byte[BufferSize]; Array.Copy(SomeByteArray, 0, buff, 0, BufferSize); handle = GCHandle.Alloc(buff, GCHandleType.Pinned); MyStuff = (NewStuff)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(NewStuff)); handle.Free();
有更好的方法来做到这一点吗?
使用BinaryReader类会比固定内存和使用Marshal.PtrStructure带来任何性能提升吗?
解决方案
回答
如果我们有一个byte [],则应该可以使用BinaryReader类,并使用可用的ReadX方法在NewStuff上设置值。
回答
从这种情况下我可以看到,我们不需要将SomeByteArray
复制到缓冲区中。我们只需要从SomeByteArray
获取句柄,将其固定,使用PtrToStructure
复制IntPtr
数据,然后释放即可。无需副本。
那将是:
NewStuff ByteArrayToNewStuff(byte[] bytes) { GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned); try { NewStuff stuff = (NewStuff)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(NewStuff)); } finally { handle.Free(); } return stuff; }
通用版本:
T ByteArrayToStructure<T>(byte[] bytes) where T: struct { T stuff; GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned); try { stuff = (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T)); } finally { handle.Free(); } return stuff; }
更简单的版本(需要unsafe
开关):
unsafe T ByteArrayToStructure<T>(byte[] bytes) where T : struct { fixed (byte* ptr = &bytes[0]) { return (T)Marshal.PtrToStructure((IntPtr)ptr, typeof(T)); } }
回答
注意包装问题。在该示例中,我们给出的所有字段都位于明显的偏移处,因为所有内容均位于4字节边界上,但情况并非总是如此。默认情况下,Visual C ++在8个字节的边界上打包。