Lesen eines C / C ++ Datenstruktur in C # von einem Byte-Array

stimmen
65

Was wäre der beste Weg, um einen C # struct von einem byte [] Array, in dem die Daten aus einem C / C ++ struct waren zu füllen? Die C-Struktur würde in etwa so aussehen (mein C ist sehr rostig):

typedef OldStuff {
    CHAR Name[8];
    UInt32 User;
    CHAR Location[8];
    UInt32 TimeStamp;
    UInt32 Sequence;
    CHAR Tracking[16];
    CHAR Filler[12];
}

Und würde wie folgt füllen:

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

Was ist am besten Weg kopieren OldStuffzu NewStuff, wenn OldStuffals byte [] Array übergeben wurde?

Ich bin derzeit so etwas wie die folgenden zu tun, aber es fühlt sich irgendwie klobig.

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

Gibt es eine bessere Art und Weise, dies zu erreichen?


Würde mit der BinaryReaderbieten Klasse keine Performance - Gewinne über die Speicher Pinning und mit Marshal.PtrStructure?

Veröffentlicht am 05/08/2008 um 22:19
quelle vom benutzer
In anderen Sprachen...                            


5 antworten

stimmen
88

Von dem, was ich in diesem Zusammenhang sehen, brauchen Sie nicht zu kopieren , SomeByteArrayin einen Puffer. Sie müssen einfach von den Griff zu bekommen SomeByteArray, stecken Sie es, kopieren Sie die IntPtrDaten mit Hilfe PtrToStructureund dann loslassen. Keine Notwendigkeit für eine Kopie.

Das wäre:

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

Generische Version:

T ByteArrayToStructure<T>(byte[] bytes) where T: struct 
{
    GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
    try
    {
        T stuff = (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T));
    }
    finally
    {
        handle.Free();
    }
    return stuff;
}

Einfachere Version (erfordert unsafeSchalter):

unsafe T ByteArrayToStructure<T>(byte[] bytes) where T : struct
{
    fixed (byte* ptr = &bytes[0])
    {
        return (T)Marshal.PtrToStructure((IntPtr)ptr, typeof(T));
    }
}
Beantwortet am 05/08/2008 um 22:29
quelle vom benutzer

stimmen
4

Hier ist eine Ausnahme sichere Version der akzeptierten Antwort :

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();
    }
}
Beantwortet am 24/01/2017 um 18:40
quelle vom benutzer

stimmen
4

Achten Sie auf Verpackungsfragen aus. Im Beispiel gab man alle Felder auf den offensichtlichen Offsets sind, weil alles auf 4 Byte-Grenzen ist, aber dies wird nicht immer der Fall sein. Visual C ++ auf 8-Byte-Grenzen von Standard Pack.

Beantwortet am 31/08/2008 um 11:03
quelle vom benutzer

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

Nimm das

Beantwortet am 11/12/2011 um 12:46
quelle vom benutzer

stimmen
0

Wenn Sie ein byte [] haben sollten Sie in der Lage sein, die Binary Klasse zu verwenden und die eingestellten Werte auf NeuerKram die verfügbaren READX Methoden.

Beantwortet am 05/08/2008 um 22:24
quelle vom benutzer

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more