在 C# 字节数组中高效处理 C/C 数据结构
C# 和 C/C 之间的互操作通常需要数据结构转换。 本文介绍了以字节数组形式接收数据并将其转换为可用的 C# 结构体的常见场景。
字节数组数据结构的解析策略
C# 中成功从字节数组解析 C/C 结构的关键在于以下步骤:
匹配 C# 结构体定义: 创建一个镜像 C/C 结构体布局的 C# 结构体。 使用 [StructLayout]
和 [FieldOffset]
.
内存固定:使用GCHandle
来固定字节数组,防止垃圾收集在解析过程中重新定位它。
直接内存转换: 使用 Marshal.PtrToStructure
直接将固定内存地址转换为您定义的 C# 结构体。 与其他方法相比,这提供了卓越的性能。
内存释放: 至关重要的是,使用 handle.Free()
释放固定内存,以避免数据处理后发生内存泄漏。
说明性示例:C 到 C# 结构体转换
让我们考虑一个 C 结构体 (OldStuff
) 及其等效的 C# 结构体 (NewStuff
):
C 结构:
<code class="language-c++">typedef struct OldStuff { CHAR Name[8]; UInt32 User; CHAR Location[8]; UInt32 TimeStamp; UInt32 Sequence; CHAR Tracking[16]; CHAR Filler[12]; } OldStuff;</code>
C# 结构:
<code class="language-csharp">[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; // Filler is omitted in C# as it's not needed for data access. }</code>
以下 C# 方法演示了字节数组解析:
<code class="language-csharp">public NewStuff ByteArrayToNewStuff(byte[] bytes) { GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned); try { return (NewStuff)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(NewStuff)); } finally { handle.Free(); } }</code>
性能优化
虽然BinaryReader
提供了一种替代方案,但Marshal.PtrToStructure
通常通过直接转换内存地址来提供卓越的性能,避免格式解释开销。 这种直接方法对于大型数据集特别有益。
通过采用这些技术,开发人员可以实现对 C# 字节数组中嵌入的 C/C 数据结构的高效且高性能的解析。
以上是如何在C#中高效地从字节数组中解析C/C数据结构?的详细内容。更多信息请关注PHP中文网其他相关文章!