2012-03-24 13 views
21

मुझे यकीन है कि एफएफआई के माध्यम से सरणी भेजना संभव है, लेकिन मुझे कोई उदाहरण नहीं मिल रहा है। उदाहरण के लिए, मेरे पास एक हास्केल सरणी है जिसे मैं int foo(int*) फ़ंक्शन पर भेजता हूं, या मेरे पास एक सी सर int bar[64]; है जिसे मैं हास्केल भेजता हूं।क्या एफएफआई सरणी के साथ सौदा कर सकता है? यदि हां, तो कैसे?

आदर्श रूप में मैं सबसे प्रभावी तरीका चाहता हूं - मुझे कोई ढेर आवंटन या अनावश्यक प्रतिलिपि नहीं चाहिए। साथ ही, यह अच्छा होगा अगर मैं हास्केल और सी दोनों में हास्केल के अनबॉक्स किए गए सरणी का उपयोग कर सकता हूं तो ऐसा करने का तरीका क्या है?

+0

सी [ 'Foreign.Marshal.Array'] (http://hackage.haskell.org/ पैकेज/आधार 4.7.0.0/docs/विदेशी मार्शल-Array.html)। – MasterMastic

उत्तर

18

यदि आप डेटा का उपयोग करते हैं। वेक्टर लाइब्रेरी आप डेटा.वेक्टर का उपयोग कर सकते हैं। आपकी आवश्यकताओं के लिए स्टाइल। फिर आप अंतर्निहित विदेशी सूचक तक पहुंचने के लिए unsafeToForeignPtr या unsafe जैसे फ़ंक्शंस का उपयोग कर सकते हैं। यह आपको किसी भी प्रतिलिपि या मार्शलिंग के बिना सी-कोड कॉल करने की अनुमति देता है।

यदि आप सी-सरणी से वेक्टर बनाना चाहते हैं तो आप unsafeFromForeignPtr का उपयोग कर सकते हैं।

अपने उदाहरण आप उपयोग कर सकते हैं (यह मानते हुए c_foo यह तर्क संशोधित नहीं करता है) के लिए

import Foreign.Ptr 
import Foreign.C.Types 
import System.IO.Unsafe (unsafePerformIO) 
import qualified Data.Vector.Storable as SV 

foreign import ccall unsafe "foo" c_foo :: Ptr CInt -> CInt 

haskellFoo :: SV.Vector CInt -> CInt 
haskellFoo sv = unsafePerformIO $ 
    SV.unsafeWith sv $ \ptr -> return (c_foo ptr) 

यह करने के लिए golfed जा जा सकता है:

haskellFoo sv = unsafePerformIO $ 
    SV.unsafeWith sv (return . c_foo) 

ध्यान रखें कि आपके सी समारोह डेटा को संशोधित करता है, तो , तो आपको यह नहीं करना चाहिए, इसके बजाय आपको संदर्भित पारदर्शिता को तोड़ने के लिए डेटा की एक प्रति बनाना चाहिए।

यदि आप मानक ऐरे-प्रकार का उपयोग करना चाहते हैं तो आप withStorableArrayData.Array.Storable से उसी तरह उपयोग कर सकते हैं।

+0

आपका गोल्फ संस्करण 'sv' पैरामीटर का उपयोग नहीं करता है, मैं अनुमान लगा रहा हूं कि आपने इसे गलती से छोड़ा है (मैंने आपके उत्तर को संपादित करने का प्रयास किया है, लेकिन एसओ ने मेरा संपादन ins 6 वर्णों को जोर दिया :() –

+1

@benmachine: आपके लिए यह तय किया गया है :) – ehird

+0

@ehird, benmachine: संपादन के लिए धन्यवाद। – dnaq

10

एफएफआई विनिर्देश काफी पठनीय है, इसलिए आप बस बैठकर पूरी चीज के माध्यम से काम करना चाहेंगे। हालांकि, इस विशिष्ट प्रश्न के लिए, आप "मार्शलिंग" अनुभाग, विशेष रूप से Ptr और Storable उपखंडों पर जा सकते हैं, जो इसके लिए क्या उपलब्ध है, इसकी रूपरेखा तैयार कर सकते हैं।

3

सी में, एक सरणी मूल रूप से सरणी के पहले सदस्य के लिए एक सूचक है। आप पॉइंटर पर अंकगणित करके अन्य तत्व प्राप्त करते हैं। PtrNum का सदस्य है, इसलिए आप सामान्य अंकगणितीय परिचालनों का उपयोग कर सकते हैं।

+5

सच है, लेकिन बास्क * में हास्केल पॉइंटर अंकगणितीय काम करता है। तो सी में, जहां आप सरणी के अगले तत्व पर जाने के लिए 'aPtr + = 1' लिखेंगे, हैस्केल में आपको' next = aPtr + 1 * sizeOf element' लिखना होगा। या आप 'Foreign.Marshal.Array.advancePtr' का उपयोग कर सकते हैं। –

+0

हाँ। यह निश्चित रूप से सच है। – fuz

+0

जब मैं 'विदेशी' या 'विदेशी.पीआरटी' आयात करता हूं, तो मुझे 'पीआरटी' के लिए 'संख्या 'का उदाहरण नहीं दिखाई देता है, जहां से आप इसे प्राप्त कर रहे हैं? –

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