एक बाइट सरणी से सी # में सी / सी ++ डेटा संरचना पढ़ना

एक बाइट [] सरणी से सी # स्ट्रक्चर भरने का सबसे अच्छा तरीका क्या होगा जहां डेटा सी / सी ++ स्ट्रक्चर से था? सी संरचना इस तरह कुछ दिखाई देगी (मेरा सी बहुत जंगली है):

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

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 का उपयोग करने पर किसी भी प्रदर्शन लाभ प्रदान करेगा?

0
जोड़ा संपादित
विचारों: 5
संरचना के स्तर पर आप इसे कैसे संभालेंगे, यानी संरचना में प्रत्येक मान के लिए बाइट्स को व्यक्तिगत रूप से उलट किए बिना?
जोड़ा लेखक Pat, स्रोत
एफवाईआई, यदि आपका प्रोग्राम विभिन्न मशीनों पर चलता है तो आपको छोटे बनाम बड़े एंडियन को संभालने की आवश्यकता हो सकती है।
जोड़ा लेखक KPexEA, स्रोत

5 उत्तर

उस संदर्भ में जो मैं देख सकता हूं, उससे आपको SomeByteArray को एक बफर में कॉपी करने की आवश्यकता नहीं है। आपको बस SomeByteArray से हैंडल प्राप्त करने की आवश्यकता है, इसे पिन करें, Inttrtr डेटा 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(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;
}

सरल संस्करण (<�कोड> असुरक्षित स्विच की आवश्यकता है):

unsafe T ByteArrayToStructure(byte[] bytes) where T : struct
{
    fixed (byte* ptr = &bytes[0])
    {
        return (T)Marshal.PtrToStructure((IntPtr)ptr, typeof(T));
    }
}
0
जोड़ा
CS0411 विधि 'ByteArrayToStructure (बाइट [], int)' के लिए प्रकार तर्क, उपयोग से अनुमानित नहीं किया जा सकता है। प्रकार तर्कों को स्पष्ट रूप से निर्दिष्ट करने का प्रयास करें। (मैंने बाइट सरणी की int अनुक्रमणिका जोड़ा) इसे करने के लिए।
जोड़ा लेखक SSpoke, स्रोत
अपवादों की उपस्थिति में स्मृति रिसाव होगा। देखें: एक सुरक्षित संस्करण के लिए stackoverflow.com/a/41836532/184528
जोड़ा लेखक cdiggins, स्रोत
4.5.1 के अनुसार, PtrToStructure का एक सामान्य संस्करण है, इसलिए उपरोक्त जेनेरिक संस्करण में दूसरी पंक्ति बन सकती है: var stuff = Marshal.PtrToStructure (handle.AddrOfPinnedObject ());
जोड़ा लेखक RobinHood70, स्रोत

स्वीकृत उत्तर का अपवाद सुरक्षित संस्करण यहां दिया गया है:

public static T ByteArrayToStructure(byte[] bytes) where T : struct
{
    var handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
    try {
        return (T) Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T));
    }
    finally {
        handle.Free();
    }
}
0
जोड़ा

यदि आपके पास बाइट है [] आप उपलब्ध रीडएक्स विधियों का उपयोग करके BinaryReader क्लास का उपयोग करने और न्यूस्टफ पर मान सेट करने में सक्षम होना चाहिए।

0
जोड़ा

पैकिंग मुद्दों के लिए बाहर देखो। उदाहरण में आपने सभी फ़ील्ड स्पष्ट ऑफ़सेट पर हैं क्योंकि सब कुछ 4 बाइट सीमाओं पर है लेकिन यह हमेशा मामला नहीं होगा। डिफ़ॉल्ट रूप से 8 बाइट सीमाओं पर दृश्य सी ++ पैक।

0
जोड़ा
"विज़ुअल सी ++ डिफ़ॉल्ट रूप से 8 बाइट सीमाओं पर पैक करता है।" यह मेरी समस्या हल हो गया, बहुत बहुत धन्यवाद!
जोड़ा लेखक Chris L, स्रोत
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;
}   

ये लो

0
जोड़ा