বাইট অ্যারে থেকে সি # তে একটি সি / সি ++ ডেটা কাঠামো পড়া


86

বাইট [] অ্যারে যেখানে সি / সি ++ স্ট্রাক্ট থেকে ডেটা ছিল সেখান থেকে সি # স্ট্রাক্ট পূরণের সর্বোত্তম উপায় কী হবে? সি স্ট্রাক্টটির মতো দেখতে কিছুটা হবে (আমার সি খুব মরিচা):

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করার সর্বোত্তম উপায় কী ?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?


4
এফওয়াইআই, যদি আপনার প্রোগ্রামটি বিভিন্ন মেশিনে চলে তবে আপনাকে সামান্য বনাম বড় এন্ডিয়ান পরিচালনা করতে হবে to
কেপেক্সএএ

4
আপনি স্ট্রাক্টের স্তরে কীভাবে হ্যান্ডেল করতে পারবেন, অর্থাত্ স্ট্রাক্টের প্রতিটি মানের জন্য আলাদাভাবে বাইটগুলি বিপরীত না করে?
প্যাট

উত্তর:


114

আমি সেই প্রসঙ্গে যা দেখতে পাচ্ছি তার থেকে আপনার 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));
    }
}

CS0411 পদ্ধতি 'বাইটআরারিটোস্ট্রাকচার <T> (বাইট [], ইনট)' এর জন্য টাইপ আর্গুমেন্টগুলি ব্যবহার থেকে অনুমান করা যায় না। প্রকারের আর্গুমেন্টগুলি স্পষ্ট করে উল্লেখ করার চেষ্টা করুন। এটিতে আমি বাইট অ্যারের ইনড ইনডেক্স যুক্ত করেছি।
এসএসপোক

ব্যতিক্রমের উপস্থিতিতে স্মৃতি ফাঁস হবে। সুরক্ষিত সংস্করণের জন্য দেখুন: stackoverflow.com/a/41836532/184528
cdiggins

4
4.5.1 হিসাবে, পিটিআরটোস্ট্রাক্টরের জেনেরিক সংস্করণ রয়েছে, সুতরাং উপরের জেনেরিক সংস্করণে দ্বিতীয় লাইনটি হয়ে উঠতে পারে: var stuff = Marshal.PtrToStructure<T>(handle.AddrOfPinnedObject());

10

গৃহীত উত্তরের একটি ব্যতিক্রম নিরাপদ সংস্করণ এখানে :

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
@ বেন-কলিন্স আমি উত্তর যুক্ত করার পরে গ্রহণযোগ্য উত্তরটি সম্পাদিত হয়েছিল।
cdiggins

5

প্যাকিংয়ের সমস্যাগুলির জন্য নজর রাখুন। উদাহরণস্বরূপ আপনি সমস্ত ক্ষেত্রটি সুস্পষ্ট অফসেটে দিয়েছেন কারণ সবকিছু 4 বাইট সীমানায় থাকে তবে এটি সর্বদা ক্ষেত্রে হবে না। ডিফল্টরূপে 8 বাইট সীমানায় ভিজ্যুয়াল সি ++ প্যাকগুলি।


4
" ডিফল্টরূপে 8 বাইট সীমানায় ভিজ্যুয়াল সি ++ প্যাকগুলি ।" এটি আমার সমস্যা সমাধান করেছে, অনেক ধন্যবাদ!
ক্রিস এল

4
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

আপনার যদি বাইট থাকে [] আপনার বাইনারিআডার ক্লাসটি ব্যবহার করতে সক্ষম হবে এবং উপলব্ধ রেডএক্স পদ্ধতিগুলি ব্যবহার করে নিউস্টাফের উপর মান সেট করতে হবে।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.