首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >从字节数组读取C#中的C/C++数据结构

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

Stack Overflow用户
提问于 2008-08-05 21:19:03
回答 5查看 60K关注 0票数 91

从数据来自C/C++结构的byte[]数组填充C#结构的最佳方法是什么?C结构看起来像这样(我的C非常生疏):

代码语言:javascript
复制
typedef OldStuff {
    CHAR Name[8];
    UInt32 User;
    CHAR Location[8];
    UInt32 TimeStamp;
    UInt32 Sequence;
    CHAR Tracking[16];
    CHAR Filler[12];
}

并会填入如下内容:

代码语言:javascript
复制
[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的最佳方法是什么?

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

代码语言:javascript
复制
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();

有没有更好的方法来实现这一点?

与固定内存和使用Marshal.PtrStructure相比,使用BinaryReader类会带来性能上的提升吗

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2008-08-05 21:29:40

根据我在该上下文中看到的,您不需要将SomeByteArray复制到缓冲区中。您只需从SomeByteArray获取句柄,固定它,使用PtrToStructure复制IntPtr数据,然后释放即可。不需要拷贝。

这将是:

代码语言:javascript
复制
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;
}

通用版本:

代码语言:javascript
复制
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开关):

代码语言:javascript
复制
unsafe T ByteArrayToStructure<T>(byte[] bytes) where T : struct
{
    fixed (byte* ptr = &bytes[0])
    {
        return (T)Marshal.PtrToStructure((IntPtr)ptr, typeof(T));
    }
}
票数 122
EN

Stack Overflow用户

发布于 2017-01-25 02:40:34

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

代码语言:javascript
复制
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();
    }
}
票数 11
EN

Stack Overflow用户

发布于 2008-08-31 10:03:39

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

票数 7
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/2871

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档