इंटेक को बाइट से कैसे प्राप्त करें [] C # में


127

मैं byte[]एक विधि में एक पारित करने के लिए IntPtrसी # में एक पैरामीटर लेता है , क्या यह संभव है और कैसे?


क्या आप अधिक विवरण प्रदान कर सकते हैं? आप इसे क्यों करना चाहेंगे?
ग्रेजेनियो

2
आपको इसकी आवश्यकता है यदि आप उदाहरण के लिए DirectShow API का उपयोग करते हैं ... VideoRenderer से डेटा प्राप्त करने के लिए, आपको इसका उपयोग करना होगा ... और GCHandleविधि एक आकर्षण की तरह काम करती है ... fixedविधि भी । : पी :))
सिपि

आपको ऐसी किसी भी चीज़ की ज़रूरत है जो डेटा की टेराबाइट्स को स्थानांतरित कर रही है और आप अतिरिक्त प्रतिलिपि से बचना चाहते हैं। अपनी कल्पना का प्रयोग।
ब्रेन २२

जवाबों:


93

किसी सरणी में IntPtr प्राप्त करने के बारे में निश्चित नहीं है, लेकिन आप Mashal.Cl का उपयोग करके अप्रबंधित कोड के साथ उपयोग के लिए डेटा की प्रतिलिपि बना सकते हैं:

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

वैकल्पिक रूप से आप एक संपत्ति के साथ एक संरचना की घोषणा कर सकते हैं और फिर मार्शल का उपयोग कर सकते हैं। PtrToStructure, लेकिन यह अभी भी अप्रबंधित स्मृति को आवंटित करने की आवश्यकता होगी।

संपादित करें: इसके अलावा, जैसा कि टायलिस ने बताया, यदि आप असुरक्षित कोड आपके लिए एक विकल्प हैं, तो आप निश्चित का भी उपयोग कर सकते हैं


बस स्पष्ट करने के लिए, Marshal.Copyउस अधिभार के साथ एक शुरुआत सूचकांक की आवश्यकता होती है। कॉल होना चाहिएMarshal.Copy(bytes, 0, unmanagedPointer, bytes.Length);
mkenyon

नई मेमोरी बनाए बिना IntPtr को प्राप्त करने के लिए बेहतर है, जैसे @ user65157 का उत्तर।
लिन

208

दूसरा रास्ता,

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

1
@ एरिक लिपिपर्ट्स अन्य पोस्ट में से प्रति एक, इसमें GC का उपयोग करने के बजाय फिक्स्ड कीवर्ड होना चाहिए
goodguys_activate

बहुत बहुत धन्यवाद। काम अच्छा है और इसके बहुत आसान है। मैं GCHandles और Marshal में इतना कुशल नहीं हूं। क्या कोई मुझे बता सकता है कि क्या प्लस के पास मार्शल है और क्या जीसीएंडल है और कौन सा उपयोग करता है? साभार
सूअर का बच्चा

1
क्या कोई एरिक लिपर्ट पोस्ट का संदर्भ दे सकता है?
कैमरन

3
@ पग्गी: मुझे लगता है कि मार्शल का नुकसान यह है कि आपको अपने डेटा की एक प्रति बनानी होगी (जिसमें आपको बहुत समय लग सकता है और आपकी ज़रूरत की बर्बादी भी हो सकती है)
Riki

6
@ makerofthings7 मुझे विश्वास नहीं है कि Lippert जीसी [वस्तुओं को पिन करने के लिए] के बजाय 'फिक्स्ड' का उपयोग करने के लिए कह रहा है, मेरा मानना ​​है कि वह कह रहा है कि किसी वस्तु को अनिश्चित काल तक पिन करने के लिए जीसी का उपयोग न करें, साथ ही कहा कि निश्चित समय का उपयोग न करें वही, या तो।
कैमरून

129

यह काम करना चाहिए लेकिन असुरक्षित संदर्भ में उपयोग किया जाना चाहिए:

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

सावधान, आपको निर्धारित ब्लॉक में सूचक का उपयोग करना होगा! एक बार जब आप निर्धारित ब्लॉक में नहीं होते हैं, तो जीसी ऑब्जेक्ट को स्थानांतरित कर सकता है।


16
मुझे यह उत्तर पसंद है क्योंकि इसमें डेटा को एक्सेस करने के लिए अतिरिक्त मेमोरी आवंटित करना शामिल नहीं है
Xcalibur

3
यह सबसे अच्छा जवाब है अगर बड़े बाइट [] का उपयोग किया जाता है। एक कॉपी में बहुत ज्यादा ओवरहेड है
goodguys_activate

19

आप Marshal.UnsafeAddrOfPinnedArrayElement(array, 0)सरणी में मेमोरी पॉइंटर प्राप्त करने के लिए उपयोग कर सकते हैं ।


1
यह है - मुझे लगता है - एक सरणी तत्व के लिए एक इंटप्रेट प्राप्त करने का एकमात्र तरीका जो 0 वें (असुरक्षित कोड का उपयोग किए बिना) नहीं है।
गुइडो डोमिनिकी

5
इस कोड को विश्वसनीय बनाने के लिए पहले msdn.microsoft.com/en-us/library/3k4y07x3.aspx
sergtk

13

यहां @ user65157 के उत्तर (उस के लिए +1, BTW) पर एक ट्विस्ट है:

मैंने पिन की गई वस्तु के लिए एक आइडीएसोपॉली रैपर बनाया:

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

यह स्वीकृत उत्तर का अधिक अयोग्य डुप्लिकेट है। आप एक साथ सभी के बजाय बाइट-बाय-बाइट की नकल क्यों करेंगे?
BDL

मुझे अपने कोड में स्वीकृत उत्तर में त्रुटि मिली। मैंने C # dll फ़ंक्शन को c # में बुलाया। c * पैरामीटर का उपयोग c ++ में किया जाता है, इसलिए मैंने स्वीकृत पद्धति का उपयोग किया। [DllImport ("MyDll.dll", EntryPoint = "functionName", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] लेकिन अजीब है, जब स्वीकार किए जाते हैं विधि का उपयोग करते हुए, सही IntPtr नहीं मिल सकता है, मुझे कुछ बफर टूट गया। , कुछ बफर को यूनिकोड के रूप में प्रदर्शित किया गया था। इसलिए मैंने इस विधि का इस्तेमाल किया
nexdev

-6

कुछ मामलों में आप Int32 के मामले में एक Int32 प्रकार (या Int64) का उपयोग कर सकते हैं। यदि आप कर सकते हैं, तो एक और उपयोगी वर्ग BitConverter है। आप जो चाहते हैं, उसके लिए आप BitConverter.ToInt32 का उपयोग कर सकते हैं।


14
आपको कभी भी, सूचक की जगह Int32 या Int64 का उपयोग नहीं करना चाहिए । यदि आपको अपना कोड किसी भिन्न प्लेटफ़ॉर्म (32-बिट-> 64-बिट) में पोर्ट करना है, तो आपके पास सभी प्रकार के सिरदर्द होंगे।
xxbbcc

5
नहीं, कोई वैध मामला नहीं है जिसमें आप Int32एक संकेतक के रूप में सही और सुरक्षित रूप से उपयोग कर सकते हैं । यह सालों पहले किया गया एक बुरा अभ्यास था और यह सभी प्रकार के पोर्टिंग मुद्दों को जन्म देता है। यहां तक ​​कि एक Int64सुरक्षित भी नहीं है क्योंकि पहले से ही 128-बिट आर्किटेक्चर हैं और सूचक आकार में वृद्धि होगी। पॉइंटर्स को केवल पॉइंटर्स के रूप में दर्शाया जाना चाहिए।
xxbbcc

1
मैंने इसे बिना समस्याओं के .NET CF प्रोजेक्ट्स में उपयोग किया, निश्चित रूप से आपको समस्या होगी यदि आप इसे अन्य सिस्टम में पोर्ट करने का प्रयास करते हैं, लेकिन कोड आउट है जिसका मतलब कभी पोर्ट नहीं किया जाना है।
एलेजांद्रो मेज़कुआ

यह सच है कि कुछ कोड को पोर्ट किए जाने की योजना नहीं है लेकिन चीजें बहुत जल्दी बदल सकती हैं। यहां तक ​​कि अगर सीएफ पर आपका उपयोग उचित था (मुझे नहीं पता) यह अभी भी एक सामान्य प्रश्न की बुरी सलाह है। का उपयोग कर के लिए ही मान्य परिदृश्य int/ longसंकेत के लिए है जब उपयोग की गई भाषा (उदाहरण के VB6 के लिए) उनमें से कोई अवधारणा नहीं है। C # पॉइंटर्स को सपोर्ट करता है और है IntPtr- इसमें intपॉइंटर की जगह कभी भी इस्तेमाल करने की कोई जरूरत नहीं है । यदि आप अपने चेतावनियों में संभावित चेतावनियों और संभावित मुद्दों की व्याख्या जोड़ते हैं तो मैं अपना -1 हटा दूंगा।
15x पर xxbbcc

3
ठीक है, आप सी # में पॉइंटर्स का उपयोग करने के बारे में इस सामान्य प्रश्न के लिए बहुत विशिष्ट मार्श कोडिंग के उपयोग की तुलना कर रहे हैं । सामान्य C # में ऐसा कोई परिदृश्य नहीं है जहाँ यह मान्य होगा। मुझे पता है कि यह एक पुराना सवाल है, लेकिन मैंने इसे नीचे वोट दिया क्योंकि मैं एक इंटप्राट के लिए मेमोरी आवंटित करने के तरीके को देखकर इसके पार आया था - अन्य लोग इसे भी देखेंगे। मैं आपकी सलाह को बहुत खतरनाक मानता हूं क्योंकि लोग यह सोचकर चले जाते हैं कि वे एक समस्या को आसानी से हल कर लेते हैं जब उन्हें सब मिल जाता है तो भविष्य में परेशानी होती है।
xxbbcc
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.