데이터가 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;
}
byte [] 배열로 전달 된 경우 에 복사 OldStuff
하는 가장 좋은 방법은 무엇입니까 ?NewStuff
OldStuff
나는 현재 다음과 같은 것을하고 있지만 다소 투박한 것 같습니다.
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
고정하고을 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));
}
}
답변
다음은 허용되는 답변 의 예외 안전 버전입니다 .
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();
}
}
답변
포장 문제에주의하십시오. 예제에서 모든 필드가 4 바이트 경계에 있기 때문에 모든 필드가 명백한 오프셋에 있지만 항상 그런 것은 아닙니다. Visual C ++ 팩은 기본적으로 8 바이트 경계에 있습니다.
답변
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에 값을 설정할 수 있어야합니다.