2016-02-27 10 views
5

मेरे पास एक बाइट है। बफर जो मैं बाइनरी। राइट() फ़ंक्शन का उपयोग कर डेटा के साथ पैक करता हूं। मुझे फिर इस बाइट सरणी को सी फ़ंक्शन में भेजने की आवश्यकता है। गो 1.6 का उपयोग करना मैं इसे समझने में सफल नहीं रहा हूं।कनवर्ट करें [] बाइट को सी * char

panic: runtime error: cgo argument has Go pointer to Go pointer 

सी समारोह:

int the_function(const void *data, int nbytes); 

मैं प्राप्त करने में सक्षम था काम करने के लिए निम्नलिखित है, लेकिन यह गलत महसूस किया

buf := new(bytes.Buffer) //create my buffer 
.... 
binary.Write(buf, binary.LittleEndian, data) //write my data to buffer here 
addr := (*C.uchar)(unsafe.Pointer(&buf.Bytes()[0])) //convert buffers byte array to a C array 
rc := C.the_function(addr, C.int(buf.Len())) //Fails here 

यह सी समारोह बुला लाइन कह पर विफल रहता है बाइट सरणी को एक स्ट्रिंग में परिवर्तित करना। क्या ऐसा करने के लिए इससे अच्छा तरीका है? क्या यह विधि डेटा पर साइड इफेक्ट्स का जोखिम उठाती है?

addr := unsafe.Pointer(C.CString(string(buf.Bytes()[0])) 

फिर इसे गो 1.6 के तहत काम करने की आवश्यकता है जो कठोर कागो सूचक नियम पेश करता है।

धन्यवाद।

उत्तर

7

यदि आप अपना पहला दृष्टिकोण उपयोग करना चाहते हैं, तो आपको फ़ंक्शन कॉल तर्कों के बाहर स्लाइस बनाने की आवश्यकता है, और अस्थायी रूप से आवंटित स्लाइस हेडर या तर्कों में बाहरी संरचना से बचने की आवश्यकता है, इसलिए cgo चेक इसे नहीं देखते हैं गो में संग्रहित एक सूचक।

b := buf.Bytes() 
rc := C.the_function(unsafe.Pointer(&b[0]), C.int(buf.Len())) 

C.CString विधि सुरक्षित हो जाएगा, कि में डेटा एक सी बफर में बनाई जाए, इसलिए कोई सूचक स्मृति जाने के लिए है, और वहाँ कोई मौका नहीं bytes.Buffer पीछे टुकड़ा संशोधित किया जाएगा है या से बाहर जाना गुंजाइश। आप पूरी स्ट्रिंग को न केवल पहले बाइट को कन्वर्ट करना चाहते हैं। इस विधियों को दो बार आवंटित करने और प्रतिलिपि करने की आवश्यकता होती है, हालांकि यदि डेटा की मात्रा कम है तो संभवतः यह कार्गो कॉल के ऊपरी हिस्से की तुलना में चिंता का विषय नहीं है।

p := C.malloc(C.size_t(len(b))) 
defer C.free(p) 

// copy the data into the buffer, by converting it to a Go array 
cBuf := (*[1 << 30]byte)(p) 
copy(cBuf[:], b) 
rc = C.the_function(p, C.int(buf.Len())) 
:

str := buf.String() 
p := unsafe.Pointer(C.CString(str)) 
defer C.free(p) 
rc = C.the_function(p, C.int(len(str))) 

तो डेटा की 2 प्रतियां कि समाधान में स्वीकार्य नहीं हैं, वहाँ एक तीसरा विकल्प है जहाँ आप malloc सी खुद बफ़र, और कहा कि बफर में एक प्रतिलिपि बनाते हैं

लेकिन उन दोनों विकल्पों के साथ, malloc'ed सूचक को मुक्त करने के लिए मत भूलना।

+0

कनवर्ट करना [] बाइट एक सी स्ट्रिंग में एक अच्छा विचार नहीं हो सकता है। चूंकि [] '[0] में [] बाइट सी स्ट्रिंग को समाप्त कर देगा, और सी स्ट्रिंग की लंबाई उत्पत्ति [] बाइट की लंबाई के बराबर नहीं हो सकती है। –

+0

@bronzeman: जाहिर है, लेकिन प्रश्न में कार्य बफर की लंबाई को तर्क के रूप में लेता है, और एक शून्य समाप्त स्ट्रिंग की अपेक्षा नहीं कर रहा है। यदि सी की आवश्यकता होती है तो 'सीसीस्ट्रिंग 'शून्य बाइट जोड़ता है, लेकिन हम सटीक स्ट्रिंग लंबाई को पार करके इसे छोड़ देते हैं। – JimB

0

आपका प्रोग्राम क्रैश हो जाता है क्योंकि सी में गुजरने वाले पॉइंटर्स के नियम go1.6 में बदल जाते हैं (विवरण के लिए https://tip.golang.org/doc/go1.6#cgo देखें)।

मुझे नहीं पता कि आपका प्रोग्राम क्रैश क्यों होता है, इसलिए मैंने गो मुद्दे https://github.com/golang/go/issues/14546 बनाया है।

लेकिन इस मुद्दे पर उत्तर देने के बावजूद, मैं बाइट्स के आंतरिक बिट्स का उपयोग नहीं करता। बफर (जैसा कि आप करते हैं) सीधे सीजीओ में जाने के लिए। बाइट्स। बफर कार्यान्वयन भविष्य में बदल सकता है, और आप प्रोग्राम रहस्यमय तरीके से तोड़ना शुरू कर देंगे। मैं केवल उस डेटा की प्रतिलिपि बनाउंगा जिसकी आपको आवश्यकता है, जो भी संरचना उचित है और इसका उपयोग गुफा में जाने के लिए करें।

एलेक्स

+0

ओपी बाइट्स के किसी भी आंतरिक बिट्स का उपयोग नहीं कर रहा है। बफर। मैंने कारण बताया, जैसा कि आपकी समस्या का डुप्लिकेट है। बफर द्वारा लौटाई गई टुकड़ा का उपयोग करने में कुछ भी गलत नहीं है – JimB

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