代码之家  ›  专栏  ›  技术社区  ›  Chris Miller

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

  •  68
  • Chris Miller  · 技术社区  · 16 年前

    从字节[]数组中填充C结构的最佳方法是什么,数据来自C/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 NewStuff 如果 老字号 作为byte[]数组传递?

    我目前正在做类似以下的事情,但感觉有点笨拙。

    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 ?

    5 回复  |  直到 6 年前
        1
  •  91
  •   15ee8f99-57ff-4f92-890c-b56153    6 年前

    从我在这方面所看到的,你不需要复制 SomeByteArray 进入缓冲区。你只需要从 某人的秘密 ,别针,复制 IntPtr 数据使用 PtrToStructure 然后释放。不需要复印件。

    那就是:

    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));
        }
    }
    
        2
  •  6
  •   Community CDub    8 年前

    这是一个异常安全版本的 accepted answer :

    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();
        }
    }
    
        3
  •  4
  •   Tim Ring    15 年前

    注意包装问题。在这个示例中,您给出的所有字段都处于明显的偏移位置,因为所有字段都在4字节边界上,但情况并非总是如此。默认情况下,Visual C++在8字节边界上进行打包。

        4
  •  3
  •   Richard J. Ross III    13 年前
    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;
    }   
    

    有这个

        5
  •  0
  •   Mufaka    16 年前

    如果有byte[],则应能够使用BinaryReader类,并使用可用的readx方法在newstuff上设置值。