태그 보관물: c#

c#

바이트 배열에서 C #의 C / C ++ 데이터 구조 읽기 구조체를 채우는

데이터가 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하는 가장 좋은 방법은 무엇입니까 ?NewStuffOldStuff

나는 현재 다음과 같은 것을하고 있지만 다소 투박한 것 같습니다.

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;
}

이것을 가지고