Čtení C / C ++ struktura dat v C # z pole bajtů

hlasů
65

Jaký by byl nejlepší způsob, jak naplnit C # struct z byte [] pole, kde byla data z C / C ++ struct? C struct bude vypadat nějak takto (můj C je velmi rezavý):

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

A zaplní asi takto:

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

Jaký je nejlepší způsob, jak kopírovat OldStuffna NewStuff, pokud OldStuffbyl schválen jako byte [] pole?

Já jsem v současné době dělá něco jako následující, ale to je trochu neohrabaný.

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

Existuje lepší způsob, jak toho dosáhnout?


By pomocí BinaryReadertřída nabídnout jakékoliv zvýšení výkonu oproti připnout paměť a používat Marshal.PtrStructure?

Položena 05/08/2008 v 22:19
zdroj uživatelem
V jiných jazycích...                            


5 odpovědí

hlasů
88

Z toho, co vidím v této souvislosti, nemusíte kopírovat SomeByteArraydo vyrovnávací paměti. Stačí jednoduše získat popisovač z SomeByteArray, připnout ji zkopírovat IntPtrdata pomocí PtrToStructurea pak jej uvolněte. Není potřeba žádná kopie.

To by bylo:

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

Generické verze:

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

Jednodušší verze (vyžaduje unsafepřepínač):

unsafe T ByteArrayToStructure<T>(byte[] bytes) where T : struct
{
    fixed (byte* ptr = &bytes[0])
    {
        return (T)Marshal.PtrToStructure((IntPtr)ptr, typeof(T));
    }
}
Odpovězeno 05/08/2008 v 22:29
zdroj uživatelem

hlasů
4

Zde je výjimka bezpečné verzi přijaté odpovědi :

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();
    }
}
Odpovězeno 24/01/2017 v 18:40
zdroj uživatelem

hlasů
4

Dejte si pozor na otázkách balících. V tomto příkladu jste dali všechna pole jsou zjevné posuny, protože všechno, co je na 4 byte hranice, ale to nemusí být vždy pravda. Visual C ++ balíčků o 8 bajtů hranice ve výchozím nastavení.

Odpovězeno 31/08/2008 v 11:03
zdroj uživatelem

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

mají tato

Odpovězeno 11/12/2011 v 12:46
zdroj uživatelem

hlasů
0

Máte-li byte [], měli byste být schopni používat třídu BinaryReader a nastavení hodnot na NewStuff pomocí dostupných metod ReadX.

Odpovězeno 05/08/2008 v 22:24
zdroj uživatelem

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