2017-05-05 15 views
9

पर बाहरी रूप से प्रदत्त बफर की प्रतिलिपि बनाने का सबसे प्रभावी तरीका क्या है, मैं ctypes का उपयोग कर बाहरी पुस्तकालय में इंटरफेसिंग कर रहा हूं। यह पुस्तकालय मुझे एक बाइनरी बफर लौटाता है। इंटरफ़ेस इस तरह दिखता है:बाइट्स

int getBuff(unsigned char **buf, int *len); 

मैं बफर जब मैं इसके साथ किया हूँ मुक्त ताकि सकता है, लेकिन है कि पहलू मेरे लिए कोई समस्या नहीं प्रस्तुत करता है, तो मुझे नहीं लगता कि हम क्या ज़रूरत है पुस्तकालय भी एक deallocator निर्यात करता है इसे कवर करने के लिए।

मेरे ctypes कोड में मैं buf तर्क c_void_p के रूप में प्रतिनिधित्व कर रहा हूं। मैं इस बफर को बाइट्स ऑब्जेक्ट में यथासंभव कुशलतापूर्वक कॉपी करना चाहता हूं।

फिलहाल मेरे पास है:

data = bytes(bytearray(ctypes.cast(buf, ctypes.POINTER(ctypes.c_ubyte*len.value))[0])) 

जहां bufc_void_p और len है c_int है।

जैसा कि मैं इसे समझता हूं, यह दो प्रतियां करता है। एक बार bytearray ऑब्जेक्ट, और फिर बाइट्स ऑब्जेक्ट के लिए।

मैं इसे केवल एक ही प्रति के साथ कैसे कर सकता हूं?

मेरे वर्तमान प्रयासों ने पाइथन 2 पर ध्यान केंद्रित किया है, लेकिन निश्चित रूप से मुझे इसे पायथन 3 के लिए भी समर्थन देना होगा।

+3

पायथन 3 पर, आपको केवल 'बाइटियर' कॉल को हटाने में सक्षम होना चाहिए। – user2357112

+1

आप 'bu_ = POINTER (c_char)' की बजाय कलाकार के साथ 'c_void_p' का उपयोग क्यों कर रहे हैं? फिर 'GetBuff (byref (buf), byref (len)) 'और' data = buf [: len.value] '। – eryksun

+0

@ एरिक्सन: हू। आप एक ctypes सूचक टुकड़ा कर सकते हैं? मेरे लिए समाचार – user2357112

उत्तर

5

स्पष्ट रूप से आप एक प्रकार के पॉइंटर को टुकड़ा कर सकते हैं। c_void_p, c_char_p, या c_wchar_p, लेकिन POINTER प्रकार काम करते हैं। एक POINTER(c_char) के लिए, यह टुकड़ा करने की क्रिया आप देता है bytes: कि को लाने के लिए eryksun को

data = ctypes.POINTER(ctypes.c_char).from_buffer(buf)[:len.value] 

धन्यवाद। साथ ही, यह स्पष्ट नहीं है कि क्यों buf है जो पहले से ही POINTER(c_char) है। (एक POINTER(c_char) के लिए, कोड सिर्फ buf[:len.value] होगा।)


एक सामान्य वस्तु बफर प्रोटोकॉल का समर्थन करता है कि से bytes हो रही के लिए, memoryview(...).tobytes()bytes(bytearray(...)) से एक कम प्रतिलिपि शामिल है:

data = memoryview(ctypes.cast(buf, ctypes.POINTER(ctypes.c_ubyte*len.value))[0]).tobytes() 

यह वह जगह है दोनों अजगर 2 और अजगर 3.


के साथ संगत ध्यान रखें कियहां बफर को पॉइंटर होने की आवश्यकता है, बफर को पॉइंटर को पॉइंटर नहीं। getBuff एक पॉइंटर को पॉइंटर लेता है (इसलिए शायद byref(buf))।

+0

धन्यवाद। हाँ डबल पॉइंटर इतना है कि लाइब्रेरी कॉलर को पॉइंटर वापस कर सकती है। लेकिन मेरे ctypes कोड buf में बफर के सूचक है। –

+0

@ एरिक्सन: मैंने एक नज़र डाली, और वाह, 'कास्ट' वास्तव में नियमित रूप से निर्मित या पायथन फ़ंक्शन के बजाय एक एफएफआई कॉल है, और यह वास्तव में आश्चर्यजनक रूप से धीमा है। पर्यावरण पर प्रति माइक्रोसॉन्ड प्रति कॉल पर मैंने इसे केवल 'कास्ट' कॉल के लिए परीक्षण किया, पॉइंटर स्लाइसिंग के लिए लगभग 67 नैनोसेकंड और 'मेमोरीव्यू (एक्स)। टोबाइट्स() 'के लिए लगभग 285 नैनोसेकंड की तुलना में (10- तत्व परीक्षण सरणी)। – user2357112

+0

@eryksun: क्या आपका मतलब 'ctypes.POINTER (ctypes.c_char) 'था, या क्या कुछ एपीआई अजीबता है जिसका मतलब है कि हमें वास्तव में' ctypes.POINTER (ctypes.c_char_p) 'का उपयोग करना चाहिए? – user2357112

संबंधित मुद्दे