从字节数组中读取 C# 中的 C/C++ 数据结构
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2871/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Reading a C/C++ data structure in C# from a byte array
提问by Chris Miller
What would be the best way to fill a C# struct from a byte[] array where the data was from a C/C++ struct? The C struct would look something like this (my C is very rusty):
从数据来自 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];
}
And would fill something like this:
并会填充这样的东西:
[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;
}
What is best way to copy OldStuff
to NewStuff
, if OldStuff
was passed as byte[] array?
如果作为 byte[] 数组传递,复制OldStuff
到的最佳方法是什么?NewStuff
OldStuff
I'm currently doing something like the following, but it feels kind of clunky.
我目前正在做类似以下的事情,但感觉有点笨拙。
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();
Is there better way to accomplish this?
有没有更好的方法来实现这一点?
Would using the BinaryReader
class offer any performance gains over pinning the memory and using Marshal.PtrStructure
?
使用BinaryReader
该类会比固定内存和使用 提供任何性能提升Marshal.PtrStructure
吗?
采纳答案by Coincoin
From what I can see in that context, you don't need to copy SomeByteArray
into a buffer. You simply need to get the handle from SomeByteArray
, pin it, copy the IntPtr
data using PtrToStructure
and then release. No need for a copy.
从我在这种情况下看到的情况来看,您不需要复制SomeByteArray
到缓冲区中。您只需要从 获取句柄SomeByteArray
,固定它,IntPtr
使用复制数据PtrToStructure
然后释放。不需要副本。
That would be:
那将是:
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;
}
Generic version:
通用版本:
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;
}
Simpler version (requires unsafe
switch):
更简单的版本(需要unsafe
开关):
unsafe T ByteArrayToStructure<T>(byte[] bytes) where T : struct
{
fixed (byte* ptr = &bytes[0])
{
return (T)Marshal.PtrToStructure((IntPtr)ptr, typeof(T));
}
}
回答by Mufaka
If you have a byte[] you should be able to use the BinaryReader class and set values on NewStuff using the available ReadX methods.
如果您有一个 byte[],您应该能够使用 BinaryReader 类并使用可用的 ReadX 方法在 NewStuff 上设置值。
回答by Tim Ring
Watch out for packing issues. In the example you gave all fields are at the obvious offsets because everything is on 4 byte boundaries but this will not always be the case. Visual C++ packs on 8 byte boundaries by default.
注意包装问题。在您给出的示例中,所有字段都在明显的偏移量处,因为所有内容都在 4 字节边界上,但情况并非总是如此。默认情况下,Visual C++ 打包在 8 字节边界上。
回答by Dushyant
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;
}
Have this
有这个
回答by cdiggins
Here is an exception safe version of the 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();
}
}