2015-05-28 12 views
15

पर एक स्ट्रिंग लौटने पर मैं जंग के लिए बहुत नया हूं। मैं एक पास्ट फ़ंक्शन से String कैसे लौटा सकता हूं जिसका उपयोग पायथन में किया जा सकता है?रास्ट फ़ंक्शन से पाइथन

use std::ffi::CString; 

#[no_mangle] 
pub extern fn query() -> CString { 
    let s = CString::new("Hello!").unwrap(); 
    return s; 
} 

और अजगर कोड है कि यह कॉल:

from ctypes import cdll, c_char_p 

lib = cdll.LoadLibrary("target/release/libtest.so") 
result = lib.query() 

print(c_char_p(result).value) 

मैं एक विभाजन गलती मिलती है, जब अपनी दौड़

यहाँ मेरी जंग कार्यान्वयन है।

संपादित करें: व्लादिमीर Matveev की जंग कोड का उपयोग नीचे मैं इसे अपने अजगर कोड में परिवर्तन के साथ काम करने के लिए मिल सकता था:

from ctypes import * 

lib = cdll.LoadLibrary("target/release/libtest.so") 
lib.query.restype = c_char_p 
result = lib.query() 
print cast(result, c_char_p).value 
lib.free_query(result) 
+0

कृपया http: // stackoverflow की समीक्षा करें।कॉम/प्रश्न/30440068/विभाजन-गलती-कब-कॉलिंग-ए-जंग-lib-with-ruby-ffi और http://stackoverflow.com/questions/30312885/pass-python-list-to-embedded-rust- फ़ंक्शन/30313295 # 30313295 और हमें बताएं कि आपका प्रश्न अलग-अलग कैसे है। – Shepmaster

+0

मैंने उन दोनों सवालों की समीक्षा की है, और वे अलग-अलग हैं। पहले में, कॉल रूबी से आता है और मेरा सवाल पायथन से है। दूसरे प्रश्न में, वापसी मूल्य एक पूर्णांक है, जो एक साधारण मामला है। यहां, वापसी विशेष रूप से एक स्ट्रिंग मान है। – LeeMobile

+1

जंग की तरफ बिल्कुल कुछ भी अलग नहीं है जिसे आप जिस भाषा से बुला रहे हैं उसके आधार पर बदलना चाहिए। जहां तक ​​जंग कोड का सवाल है, सी इसे बुला रहा है। हर दूसरी भाषा कॉल कर रही है जो सी कोड की तरह दिखती है। – Shepmaster

उत्तर

11

सबसे सीधा संस्करण इस होगा char एस का क्रम जो पाइथन के c_char_p पर पारित किया जा सकता है। आप केवल CString वापस नहीं लौट सकते हैं क्योंकि यह जंग संरचना है जिसे सी कोड में सीधे इस्तेमाल नहीं किया जाना चाहिए - यह Vec<u8> लपेटता है और वास्तव में तीन सूचक आकार के पूर्णांक होते हैं। यह सीधे सी के char* के साथ संगत नहीं है। हमें इसमें से एक कच्चा सूचक प्राप्त करने की आवश्यकता है। CString::into_raw() विधि यह करती है - यह CString मूल्य से उपभोग करती है, "भूल जाती है" इसलिए इसका आवंटन नष्ट नहीं होगा, और सरणी की शुरुआत में *mut c_char पॉइंटर लौटाता है।

हालांकि, इस तरह स्ट्रिंग लीक हो जाएगी क्योंकि हम जंग की तरफ अपना आवंटन भूल जाते हैं, और यह कभी भी मुक्त नहीं होगा। मैं पाइथन के एफएफआई को पर्याप्त नहीं जानता, लेकिन इस समस्या को ठीक करने का सबसे सीधा तरीका दो कार्यों को बनाना है, एक डेटा बनाने के लिए और इसे मुक्त करने के लिए एक। तो फिर तुम इस मुक्त कार्यप्रणाली को कॉल करके अजगर की ओर से डेटा को मुक्त करने की जरूरत है:

// above function 
#[no_mangle] 
pub extern fn query() -> *mut c_char { ... } 

#[no_mangle] 
pub extern fn free_query(c: *mut c_char) { 
    // convert the pointer back to `CString` 
    // it will be automatically dropped immediately 
    unsafe { CString::from_raw(c); } 
} 

CString::from_raw() विधि एक *mut c_char सूचक स्वीकार करता है और इसे से बाहर एक CString उदाहरण बनाता है, में अंतर्निहित शून्य समाप्त स्ट्रिंग की लंबाई की गणना प्रक्रिया। यह ऑपरेशन स्वामित्व हस्तांतरण का तात्पर्य है, इसलिए परिणामी CString मूल्य आवंटन का मालिक होगा, और जब इसे गिरा दिया जाएगा, आवंटन मुक्त हो जाता है। यह वही है जो हम चाहते हैं।

+0

मुझे इसे काम करने के लिए [here] (https://github.com/rust-lang/libc#usage) से पहले दो चरणों को करने की आवश्यकता है: (1) 'Cargo.toml' में rustc पर निर्भरता जोड़ें और (2) इसे जंग फ़ाइल में आयात करें जहां इसका उपयोग किया जाता है। (यकीन नहीं है कि यह हमेशा जरूरी है, मैं जंग के लिए पूरी तरह से नया हूँ।) – ArneHugo

1

समस्या यहाँ है कि आप एक CString लौट रहे हैं सीधे, जो ऐसा नहीं करता है C में स्ट्रिंग के प्रतिनिधित्व के अनुरूप है (आप hereCString का स्रोत कोड देख सकते हैं)।

आपको s.as_ptr() का उपयोग करके स्ट्रिंग में पॉइंटर लौटाया जाना चाहिए। हालांकि, आपको यह सुनिश्चित करने की आवश्यकता है कि फ़ंक्शन के अंत में स्ट्रिंग को डिलीओकेट नहीं किया गया है, क्योंकि इसके परिणामस्वरूप एक खतरनाक पॉइंटर होगा।

एकमात्र समाधान जिसे मैं सोच सकता हूं forget का उपयोग करना है ताकि जंग को मुक्त करने के बजाय चर को भूल जाएं। बेशक आपको स्मृति रिसाव से बचने के लिए स्ट्रिंग को मुक्त करने का एक तरीका ढूंढना होगा (व्लादिमीर का जवाब देखें)।

परिवर्तन मैंने कहा के साथ, अपने जंग कोड होना चाहिए निम्नलिखित:

use libc::c_char; 
use std::ffi::CString; 
use std::mem; 

#[no_mangle] 
pub extern fn query() -> *mut c_char { 
    let s = CString::new("Hello!").unwrap(); 
    s.into_raw() 
} 

यहाँ हम करने के लिए एक शून्य समाप्त एक सूचक लौट:

use std::ffi::CString; 
use std::mem; 

#[no_mangle] 
pub extern fn query() -> *const i8 { 
    let s = CString::new("Hello!").unwrap(); 
    let ptr = s.as_ptr(); 
    mem::forget(s); 
    return ptr; 
} 
संबंधित मुद्दे