সি # তে কীভাবে বাইট [] থেকে ইনট্রিপিআর পাবেন?


127

আমি byte[]কোনও পদ্ধতিতে পাস করতে চাই IntPtr# # তে একটি প্যারামিটার লাগে , এটি কি সম্ভব এবং কীভাবে?


আপনি আরও বিশদ সরবরাহ করতে পারেন? আপনি এটি করতে চান কেন?
— গ্রাজেনিও

2
আপনি যদি প্রয়োজন যেমন উদাহরণস্বরূপ ডাইরেক্টশো এপিআই ব্যবহার করেন ... ভিডিওরেন্ডারারের কাছ থেকে ডেটা পেতে, আপনাকে এটি ব্যবহার করতে হবে ... এবং GCHandleপদ্ধতিটি কবজির মতো কাজ করে ... fixedপদ্ধতিটিও। : পি :))
— সিপি

ডেটা টেরাবাইটের স্থানান্তর করছে এমন কোনও কিছুর জন্য আপনার এটি দরকার এবং আপনি অতিরিক্ত অনুলিপি এড়াতে চান। তোমার কল্পনা শক্তি ব্যবহার কর.
— Brain2000

উত্তর:


93

কোনও অ্যারেতে একটি ইন্টারপ্রিটি পাওয়ার বিষয়ে নিশ্চিত নন, তবে আপনি মশাল.কপি ব্যবহার করে নিয়ন্ত্রণহীন কোড সহ ডেটা অনুলিপি করতে পারেন:

IntPtr unmanagedPointer = Marshal.AllocHGlobal(bytes.Length);
Marshal.Copy(bytes, 0, unmanagedPointer, bytes.Length);
// Call unmanaged code
Marshal.FreeHGlobal(unmanagedPointer);

বিকল্পভাবে আপনি একটি সম্পত্তি সহ একটি স্ট্রাক্ট ঘোষণা করতে পারেন এবং তারপরে মার্শাল.প্রিটারটোস্ট্রাক্ট ব্যবহার করতে পারেন, তবে তার জন্য এখনও পরিচালনা না করা মেমরির বরাদ্দ প্রয়োজন।

সম্পাদনা: এছাড়াও, যেমন Tyalis নির্দিষ্ট, এছাড়াও আপনি ব্যবহার করতে পারেন নির্দিষ্ট যদি অনিরাপদ আপনি যে কোডটি জন্য একটি বিকল্প


কেবল পরিষ্কার করতে, Marshal.Copyসেই ওভারলোডের সাথে একটি সূচনা সূচক প্রয়োজন। কলটি হওয়া উচিতMarshal.Copy(bytes, 0, unmanagedPointer, bytes.Length);
— মেকইন

@ ব্যবহারকারী 65157 এর উত্তরের মতো নতুন মেমরি তৈরি না করেই ইন্টিপিটিআর পাওয়া ভাল।
— লিন

208

অন্য উপায়,

GCHandle pinnedArray = GCHandle.Alloc(byteArray, GCHandleType.Pinned);
IntPtr pointer = pinnedArray.AddrOfPinnedObject();
// Do your stuff...
pinnedArray.Free();

1
@ চিপিতে এরিক লিপার্টসের অন্যান্য পোস্টগুলির মধ্যে একটিতে, এর মধ্যে জিসি ব্যবহার না করে ফিক্সড কীওয়ার্ড থাকা উচিত
— গুডগুইস_অ্যাক্টিভেট

অনেক ধন্যবাদ. সুন্দর কাজ করুন এবং এটি বেশ সহজ। আমি GCHandles এবং মার্শালে তেমন দক্ষ নই। কেউ আমাকে বলতে পারবেন কি মার্শাল আছে এবং কোনটি GCHandle আছে এবং কোনটি কোনটি ব্যবহার করে? ধন্যবাদ
— পিগি

1
কেউ দয়া করে এরিক লিপার্ট পোস্টের রেফারেন্স সরবরাহ করতে পারেন?
— ক্যামেরন

3
@ পিগজি: আমি মনে করি মার্শালের অসুবিধা হ'ল আপনাকে আপনার ডেটাগুলির একটি অনুলিপি তৈরি করতে হবে (যা আপনার প্রয়োজন হতে পারে এমন দীর্ঘ সময় এবং মেমরির অপচয় করতে পারে)
— রিকি

6
@ makerofthings7 আমি বিশ্বাস করি না যে লিপার্ট জিসির পরিবর্তে 'স্থির' ব্যবহার করার কথা বলেছে [অবজেক্টগুলি পিন করতে], আমি বিশ্বাস করি তিনি বলছেন যে কোনও বিষয় অনির্দিষ্টকালের জন্য পিন করার জন্য জিসি ব্যবহার করবেন না, পাশাপাশি এটি করার জন্য স্থির ব্যবহার করবেন না বলেও জানান একই, হয়।
— ক্যামেরন

129

এটি কাজ করা উচিত তবে এটি অনিরাপদ প্রসঙ্গে ব্যবহার করা উচিত:

byte[] buffer = new byte[255];
fixed (byte* p = buffer)
{
    IntPtr ptr = (IntPtr)p;
    // do you stuff here
}

সাবধান, আপনি নির্দিষ্ট ব্লকে পয়েন্টার ব্যবহার করতে হবে! আপনি আর স্থির ব্লকের মধ্যে না থাকলে একবার গিসি অবজেক্টটি সরাতে পারে।


16
আমি এই উত্তরটি পছন্দ করি কারণ এটিতে কেবল ডেটা অ্যাক্সেস করতে অতিরিক্ত মেমরি বরাদ্দ করা জড়িত না
— এক্সক্যালিবুর

3
বড় বাইট [] ব্যবহার করা হলে এটি সেরা উত্তর। একটি অনুলিপিটির অনেক বেশি ওভারহেড রয়েছে
— শুভগুইস_অ্যাক্টিভেট

19

আপনি Marshal.UnsafeAddrOfPinnedArrayElement(array, 0)অ্যারেতে একটি মেমরি পয়েন্টার পেতে ব্যবহার করতে পারেন ।


1
এটি হ'ল - আমি মনে করি - অ্যারে উপাদানটির জন্য কেবলমাত্র ইন্টিপিটিআর পাওয়ার একমাত্র উপায় যা 0 তম নয় (অনিরাপদ কোড ব্যবহার না করে)।
— গাইডো ডোমেনিসি

5
এই কোডটি নির্ভরযোগ্য অ্যারে করতে প্রথমে এমএসএনএন.মাইক্রোসফটি.এইন
— ইউএস

13

এখানে @ ব্যবহারকারী 65157 এর উত্তরে একটি টুইস্ট রয়েছে (তার জন্য +1, বিটিডাব্লু):

আমি পিনযুক্ত অবজেক্টের জন্য একটি আইডিস্পোজযোগ্য মোড়ক তৈরি করেছি:

class AutoPinner : IDisposable
{
   GCHandle _pinnedArray;
   public AutoPinner(Object obj)
   {
      _pinnedArray = GCHandle.Alloc(obj, GCHandleType.Pinned);
   }
   public static implicit operator IntPtr(AutoPinner ap)
   {
      return ap._pinnedArray.AddrOfPinnedObject(); 
   }
   public void Dispose()
   {
      _pinnedArray.Free();
   }
}

তারপরে এটিকে এভাবে ব্যবহার করুন:

using (AutoPinner ap = new AutoPinner(MyManagedObject))
{
   UnmanagedIntPtr = ap;  // Use the operator to retrieve the IntPtr
   //do your stuff
}

আমি ফ্রি () :) এ কল করতে ভুলে যাবেন না এটি একটি দুর্দান্ত উপায় বলে মনে হয়েছে


4
আপনি সেফহ্যান্ডল থেকে আপনার অটোপিনারকে উত্সাহিত করতে তদন্ত করতে চাইতে পারেন যেহেতু এই শ্রেণিটি সম্মতিযুক্ত এবং সুরক্ষা "গোটচগুলি" অ্যাকাউন্টে গ্রহণ করে, পাশাপাশি প্রস্তাবিত আইডিপোজেবল প্যাটার্নটি উত্সাহিত / ব্যবহার করে।
— kkahl

0

মার্শাল.কপি কাজ করে তবে ধীর হয়। দ্রুত লুপের জন্য বাইটস অনুলিপি করা হয়। আরও দ্রুত হ'ল বাইট অ্যারেটি একটি অতি দীর্ঘ অ্যারেতে কাস্ট করা, বাইট অ্যারে অনুসারে যতটা উলং কপি করা হয়, তারপরে সম্ভাব্য অবশিষ্ট 7 বাইট (8 টি বাইট সারিবদ্ধ নয় এমন ট্রেইল) অনুলিপি করুন। দ্রুততমটি হল টায়ালিসের উত্তরে প্রস্তাবিত হিসাবে একটি নির্দিষ্ট বিবৃতিতে বাইট অ্যারে পিন করা।


-1
IntPtr GetIntPtr(Byte[] byteBuf)
{
    IntPtr ptr = Marshal.AllocHGlobal(byteBuf.Length);
    for (int i = 0; i < byteBuf.Length; i++)
    {
       Marshal.WriteByte(ptr, i, byteBuf[i]);
    }
    return ptr;
}

এটি গৃহীত উত্তরের আরও অকার্যকর সদৃশ। আপনি কেন একবারে সকলের পরিবর্তে বাইট-বাই-বাইট অনুলিপি করবেন?
— বিডিএল

আমি আমার কোডটিতে গৃহীত উত্তরে ত্রুটিটি পেয়েছি। আমি সি # তে সি ++ ডেল ফাংশন বলেছি। গৃহস্থালি * প্যারামিটার সি ++ এ ব্যবহৃত হয়েছে, তাই আমি স্বীকৃত পদ্ধতি ব্যবহার করেছি। [DllImport ("MyDll.dll", এন্ট্রিপয়েন্ট = "ফাংশননেম", চারসেট = CharSet.Ansi, কলিংকনভেনশন = কলিংকনভেনশন.সিডিএসিএল)] তবে আশ্চর্যজনক, স্বীকৃত পদ্ধতি ব্যবহার করার সময়, সঠিক ইন্ট্রিটিআর পেতে পারি না, আমি পেয়েছিলাম কিছু বাফারটি ভেঙে গেছে , কিছু বাফার ইউনিকোড হিসাবে প্রদর্শিত হয়েছিল। তাই আমি এই পদ্ধতিটি ব্যবহার করেছি
— নেক্সদেব

-6

কিছু ক্ষেত্রে আপনি ইন্টিপিটিআর ক্ষেত্রে একটি ইন্টার 32 টাইপ (বা ইন্টার 64) ব্যবহার করতে পারেন। আপনি যদি পারেন তবে অন্য দরকারী শ্রেণি হ'ল বিটকনভার্টার। আপনি যা চান তার জন্য আপনি বিটকনভার্টার ব্যবহার করতে পারেন o টুআইন্ট 32 উদাহরণস্বরূপ।


14
আপনার কখনই কোনও পয়েন্টারের জায়গায় ইন্টার 32 বা ইন্টার 64 ব্যবহার করা উচিত নয় । আপনার কোডটি যদি অন্য কোনও প্ল্যাটফর্মে (32-বিট-> 64-বিট) পোর্ট করতে হয় তবে আপনার সমস্ত ধরণের মাথা ব্যথা হবে।
— xxbbcc

5
না, এমন কোনও বৈধ মামলা নেই যেখানে আপনি সঠিকভাবে এবং নিরাপদে Int32একটি পয়েন্টার হিসাবে ব্যবহার করতে পারেন । এটি বহু বছর আগে করা একটি খারাপ অভ্যাস ছিল এবং এটি সমস্ত ধরণের পোর্টিংয়ের সমস্যার দিকে পরিচালিত করে। এমনকি একটি Int64নিরাপদ নয় কারণ ইতিমধ্যে 128-বিট আর্কিটেকচার রয়েছে এবং পয়েন্টারের আকার বৃদ্ধি পাবে। পয়েন্টারগুলিকে কেবল পয়েন্টার হিসাবে প্রতিনিধিত্ব করা উচিত।
— xxbbcc

1
আমি এটি ইস্যু ছাড়াই। নেট সিএফ প্রকল্পগুলিতে ব্যবহার করেছি, অবশ্যই আপনি যদি অন্য সিস্টেমে এটি পোর্ট করার চেষ্টা করেন তবে আপনার সমস্যা হবে, তবে সেখানে কোড রয়েছে যা কখনও পোর্ট করা উচিত নয়।
— আলেজান্দ্রো মেজকুয়া

এটি সত্য যে কিছু কোড পোর্ট করার পরিকল্পনা করা হয়নি তবে জিনিসগুলি খুব দ্রুত পরিবর্তন হতে পারে। এমনকি সিএফ-তে আপনার ব্যবহার যদি ন্যায়সঙ্গত হয় তবে (আমি জানি না) এটি এখনও জেনেরিক প্রশ্নের খারাপ পরামর্শ। পয়েন্টারগুলির জন্য int/ ব্যবহারের জন্য একমাত্র বৈধ longদৃশ্যাবলীটি যখন ব্যবহৃত ভাষার কোনও ধারণা না থাকে (উদাহরণস্বরূপ ভিবি 6)। সি # পয়েন্টারগুলিকে সমর্থন করে এবং রয়েছে IntPtr- intকখনও কোনও পয়েন্টারের জায়গায় কোনও ব্যবহার করার দরকার নেই । যদি আপনি আপনার উত্তরে স্পষ্ট সতর্কতা এবং সম্ভাব্য সমস্যার ব্যাখ্যা যোগ করেন তবে আমি আমার -1 সরিয়ে ফেলব।
— xxbbcc

3
হ্যাঁ, আপনি হয় C # পয়েন্টার ব্যবহার সম্পর্কে এই সাধারণ প্রশ্ন খুব নির্দিষ্ট marshalling কোডের ব্যবহার তুলনা। সাধারণ সি # তে এমন কোনও দৃশ্য নেই যেখানে এটি কার্যকর হবে। আমি জানি এটি একটি পুরানো প্রশ্ন তবে আমি এটিকে ভোট দিয়েছি কারণ আমি ইন্টারপ্রেটারের জন্য মেমরি বরাদ্দের উপায় সন্ধান করে এটি পেরিয়ে এসেছি - অন্যরাও এটি দেখতে পাবে। আমি আপনার পরামর্শটিকে অত্যন্ত বিপজ্জনক হিসাবে দেখছি কারণ লোকেরা ভেবে ভেবেই এটির সাথে চলে যাবে যখন তারা যা পেয়েছিল সবই ভবিষ্যতের সমস্যা হ'ল সহজেই কোনও সমস্যা সমাধানের সাথে পালিয়ে যায়।
— xxbbcc
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.