2012-02-24 15 views
6

में struct एक libx.so जो 2 काम करता है, और एक struct निर्यात नहीं है,सी अजगर

typedef struct Tag { 
    int num; 
    char *name; 
}Tag; 

Tag *create(int n, char *n) 
{ 
    Tag *t = malloc(sizeof(Tag)); 
    t->num = n; 
    t->name = n; 
    return t; 
} 

void use(Tag *t) 
{ 
    printf("%d, %s\n", t->num, t->name); 
} 

मैं अजगर में create फोन और फिर सहेजना चाहते Tag *rescreate द्वारा दिया, बाद में मैं use और पास कॉल करेंगे (बस प्रदर्शित करने के लिए) Tag *resuse से पहले बचाया, यहाँ यह है:

>>>libx = ctypes.CDLL("./libx.so") 
>>>res = libx.create(c_int(1), c_char_p("a")) 
>>>libx.use(res) 

ऊपर कोड गलत हो सकता है, बस प्रदर्शित करने के लिए जो मैं चाहता करने के लिए।

और मेरी समस्या यह है कि, मैं create द्वारा परिणाम को कैसे सहेज सकता हूं? चूंकि यह उपयोगकर्ता द्वारा परिभाषित struct पर एक सूचक देता है, और मैं पाइथन में struct Tag के समकक्ष का निर्माण नहीं करना चाहता, c_void_p चाल करेगा?

सूचक (c_char_p("a")) create को कॉल की अवधि के लिए ही मान्य है:

अद्यतन

से @ डेविड का जवाब, मैं अभी भी काफी एक बात समझ में नहीं आता। जैसे ही रिटर्न बनाएं, वह सूचक लंबा मान्य नहीं है।

और मैं create में t->name को c_char_p("a") असाइन करते हैं, जब create खत्म करने के लिए कॉल, t->name एक dangling सूचक है? चूंकि उद्धृत शब्दों के अनुसार, यह सूचक अब create के बाद मान्य नहीं है। क्यों c_char_p("a") अब मान्य नहीं है?

उत्तर

4

आपके द्वारा प्रस्तुत सी कोड बस काम नहीं करेगा। आपको पार्टी को आवंटित करने और ढेर स्मृति के लिए ज़िम्मेदार होने के बारे में और अधिक सटीक होना चाहिए।

अपने वर्तमान उदाहरण में आप सी कोड में c_char_p("a") पास करते हैं। हालांकि, उस ctypes स्मृति का सूचक केवल create पर कॉल की अवधि के लिए मान्य है। जैसे ही create लौटाता है तो वह सूचक अब मान्य नहीं है। लेकिन आपने create के अंदर पॉइंटर की एक प्रति ली। इस प्रकार use के बाद की कॉल विफल होने के लिए उत्तरदायी है।

आपको उस स्ट्रिंग की सामग्री की प्रतिलिपि लेने और इसे संरचना में संग्रहीत करने की आवश्यकता होगी। यदि आप ऐसा करते हैं तो आप सुरक्षित रूप से libx.create.restype = c_void_p का उपयोग कर सकते हैं।

लेकिन अगर आप स्मृति को आवंटित करने के लिए आवंटित आवंटित करना चाहते हैं तो आपको create फ़ंक्शन से मेल खाने के लिए destroy फ़ंक्शन प्रदान करना होगा। इन परिवर्तनों के साथ सी कोड इस तरह दिखेगा:

Tag *create(int n, char *s) 
{ 
    Tag *t = malloc(sizeof(Tag)); 
    t->num = n; 
    t->name = strdup(s); 
    return t; 
} 

void destroy(Tag *t) 
{ 
    free(t->name); 
    free(t); 
} 

अजगर कोड इस तरह दिखेगा:

libx = ctypes.CDLL("./libx.so") 
libx.create.restype = c_void_p 
res = libx.create(c_int(1), c_char_p("a")) 
libx.use(res) 
libx.destroy(res) 
+0

मैं सिर्फ मेरी पैंट –

+0

ठीक है, सर में बदबूदार चला गया, वहाँ 3 बातें मुझे समझ नहीं आता है। 1, 'उस ctypes स्मृति के सूचक केवल कॉल की अवधि के लिए वैध है।' वह क्यों है? मुझे लगता है यह क्योंकि 'create',' c_char_p ("एक") 'के रेफरी गिनती करने के लिए कॉल के बाद शून्य करने के लिए चला जाता है, सही है, तो' "एक" 'कचरा-एकत्र किया जाता है? 2, अपने कोड में, 'res' एक' c_void_p' वस्तु है, लेकिन, मैं तो बस किसी भी डाली बिना res' पारित कर सकते हैं '' सीधे libx.use' को 'libx.use' एक' टैग * 'आर्ग लेता है? 3, मुझे स्पष्ट रूप से 'नष्ट (res) 'क्यों करना चाहिए? – Alcott

+0

मैं सिर्फ एक परीक्षण चलाता हूं, ऐसा लगता है कि मेरा कोड सही ढंग से काम कर सकता है, महोदय। – Alcott

0

अजगर संदर्भ गिनती करता है। आपको "बाहरी" पुस्तकालयों से लौटाई गई वस्तुओं के लिए Py_INCREF() और मित्रों का उपयोग करना होगा।

अद्यतन: मैं अजगर द्वारा .so लोड हो रहा है, हो सकता है विधि @ दाऊद Hefferman द्वारा प्रस्तावित इस स्वतः करता है के बारे में पता नहीं है।

UPDATE2: मुझे हटाना!

+1

प्रश्न सीटीपीएस से संबंधित है जो एक विदेशी फ़ंक्शन इंटरफ़ेस है, अगर आप उसे जानते हैं तो पिनवोक के समान। 'Py_INCREF' बस प्रासंगिक नहीं है। –

+0

ठीक है। मैं हटा दूंगा – wildplasser