从字节数组中读取C#中的C / C ++数据结构

从数据来自C / C ++结构的byte []数组填充C#结构的最佳方法是什么? 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

从我可以看到在这方面,你不需要复制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 { GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned); try { T 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个字节的边界上。

以下是接受的答案的exception安全版本:

 public static T ByteArrayToStructure<T>(byte[] bytes) where T : struct { var handle = GCHandle.Alloc(bytes, GCHandleType.Pinned); try { return (T) Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T)); } finally { handle.Free(); } } 
 object ByteArrayToStructure(byte[] bytearray, object structureObj, int position) { int length = Marshal.SizeOf(structureObj); IntPtr ptr = Marshal.AllocHGlobal(length); Marshal.Copy(bytearray, 0, ptr, length); structureObj = Marshal.PtrToStructure(Marshal.UnsafeAddrOfPinnedArrayElement(bytearray, position), structureObj.GetType()); Marshal.FreeHGlobal(ptr); return structureObj; } 

拥有这个

如果你有一个byte [],你应该可以使用BinaryReader类,并使用可用的ReadX方法在NewStuff上设置值。