Program Tip

바이트 배열에서 C #의 C / C ++ 데이터 구조 읽기

programtip 2020. 10. 12. 08:04
반응형

바이트 배열에서 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한 다음 해제하면됩니다. 사본이 필요하지 않습니다.

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 T ByteArrayToStructure<T>(byte[] bytes) where T : struct
{
    fixed (byte* ptr = &bytes[0])
    {
        return (T)Marshal.PtrToStructure((IntPtr)ptr, typeof(T));
    }
}

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

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.


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


If you have a byte[] you should be able to use the BinaryReader class and set values on NewStuff using the available ReadX methods.

참고URL : https://stackoverflow.com/questions/2871/reading-a-c-c-data-structure-in-c-sharp-from-a-byte-array

반응형