ctypes

2013-07-17 12 views
5

के साथ मेमोरी एड्रेस पर डेटा एक्सेस करें मैं पुराने सी प्रोग्राम के लिए पाइथन रैपर बनाने की कोशिश कर रहा हूं जो पॉइंटर्स के रूप में इनपुट लेता है। इस बिंदु पर, मैं प्रोग्राम को चलाने के लिए प्राप्त कर सकता हूं लेकिन यह पता नहीं लगा सकता कि नामित पॉइंटर्स पर मूल्यों को वापस कैसे प्राप्त किया जाए।ctypes

यह एक सरल बनाया सी स्क्रिप्ट:

#include <stdlib.h> 

void cprogram(double *wts, double *res, int *kks, int n, double *ex) { 
    int m; 
    m=n+1; 
    res[0]=1.0; 
    kks[0]=1.0;} 

और यह है मेरी सरलीकृत अजगर कोड:

from ctypes import * 
import sys 

libc = CDLL("src/program.so") 

class CONTEXT(Structure): 
    _fields_ = [ 
       ("wts", POINTER(c_double)), //tried just to see if it would work 
       ("res", c_double), 
       ("kks", c_int), 
       ("n", c_int), 
       ("ex", c_double)] 

def runner(): 
    kk = (1,2,3) 
    n = 3 
    mm = n + 1 
    wts = (c_double * n)(1, 1, 1) 
    res = (c_double * mm)(0) 
    kks = (c_int * len(kk))(*kk) 
    n = c_int(n) 
    ex = c_double(0) 

    libc.cprogram.restype = POINTER(CONTEXT) 

    tmp = libc.cprogram(wts, res, kks, n, ex) 

runner() 

मैं print tmp[1].wts[1] और print tmp[2] तरह आदेशों की कोशिश की है लेकिन यह केवल स्मृति पते के प्रिंट और नहीं मूल्य (या अविश्वसनीय रूप से छोटे मान जो 2.15880221124e-314 की तरह गलत हैं)। मैं wts के मूल्यों की एक सूची वापस करने में सक्षम होना चाहता हूँ।

उत्तर

3

आपका सी फ़ंक्शन void देता है, CONTEXT * नहीं। तो, आपका कोड सिर्फ CONTEXT * पर यादृच्छिक अनियमित स्मृति कास्टिंग कर रहा है, और फिर इसे खराब करने का प्रयास कर रहा है।

उस के शीर्ष पर, भले ही वह संदर्भ द्वारा वापसी एक CONTEXT वस्तु किया था, tmp[1], के बाद स्मृति deref है कि वस्तु की कोशिश तो यह अभी भी कचरा होगी।

जब आप दोहरी के रूप में यादृच्छिक स्मृति की व्याख्या करने का प्रयास करते हैं, तो आप 2.15880221124e-314 जैसे सेगफाल्ट या मान प्राप्त करने जा रहे हैं यदि आप भाग्यशाली हैं- यदि आप दुर्भाग्यपूर्ण हैं, तो आपको सही दिखने वाला होगा लेकिन फिर भी यादृच्छिक मान 0.0


इस बीच, अपने सी समारोह जगह में अपने तर्कों को संशोधित करता है के बाद से, आप यहाँ कुछ भी कल्पना करने की ज़रूरत नहीं है। बस में चर आप पारित कर का उपयोग

तो:।

def runner(): 
    kk = (1,2,3) 
    n = 3 
    mm = n + 1 
    wts = (c_double * n)(1, 1, 1) 
    res = (c_double * mm)(0) 
    kks = (c_int * len(kk))(*kk) 
    n = c_int(n) 
    ex = c_double(0) 

    libc.cprogram.restype = None 

    libc.cprogram(wts, res, kks, n, ex) 

    print wts[1] 

यह काम करता है, और 1.0 बाहर प्रिंट करता है।


और अपने सी समारोह वापसी CONTEXT अपने ctypes घोषणा, यह होगा सब काम ठीक मिलान structs की एक सरणी किया है। उदाहरण के लिए:

#include <stdlib.h> 

typedef struct { 
    double *wts; 
    double res; 
    int kks; 
    int n; 
    double ex; 
} CONTEXT; 

CONTEXT *cprogram(double *wts, double *res, int *kks, int n, double *ex) { 
    int m; 
    m=n+1; 
    res[0]=1.0; 
    kks[0]=1.0; 

    CONTEXT *contexts = malloc(sizeof(CONTEXT) * 4); 
    for (int i=0; i!=4; ++i) { 
    double *wtsses = malloc(sizeof(double) * 5); 
    for (int j=0; j!=4; ++j) { 
     wtsses[j] = i + j; 
    } 
    CONTEXT context = { wtsses, *res, *kks, m, *ex }; 
    contexts[i] = context; 
    } 
    return contexts; 
} 

इस संकलित करें, एक अतिरिक्त print tmp[1].wts[1] के साथ अपने मौजूदा अजगर स्क्रिप्ट चलाने, और इसे बाहर 2.0 प्रिंट होगा।


अंत में, अपने अनुवर्ती के लिए, पहले के int *n, जहां *n इनपुट है लेने के लिए सी कोड बदलने:

void cprogram(double *wts, double *res, int *kks, int *n, double *ex) { 
    int m; 
    m=*n+1; 
    res[0]=1.0; 
    kks[0]=1.0;} 

अब, अजगर से कॉल करने के लिए, आप एक c_int बनाने के लिए और इसके लिए एक सूचक पास करें।

libc.cprogram(wts, res, kks, pointer(n), ex) 

यह भी काम करता है: चूंकि आप पहले से ही पहली छमाही कर रहे हैं (जो आवश्यक नहीं था से पहले बस के बजाय argtypes सेट ... लेकिन यह जो सुविधाजनक है अब आवश्यक है,), यह सिर्फ एक पंक्ति परिवर्तन है यदि n एक इन-आउट पैरामीटर है।


लेकिन वास्तव में, आपको पाइथन से पॉइंटर ऑब्जेक्ट को देखने की आवश्यकता नहीं है; एकमात्र चीज जो आप कर रहे हैं वह इसे फ़ंक्शन को पास करने के लिए बना रही है, फिर इसे एकत्रित करने दें। एक ctypes सूचक वस्तु (जो फिर से काम करता है, भले ही n एक में बाहर पैरामीटर है) बनाने के बिना एक सी सूचक पारित करने के लिए, byref का उपयोग करें:

libc.cprogram(wts, res, kks, byref(n), ex) 
+0

समय और प्रयास में डालने की व्याख्या और मेरी त्रुटियों को ठीक करने के लिए धन्यवाद ! मुझे मिली एकमात्र चीज यह थी कि 'c_void' मौजूद नहीं प्रतीत होता है लेकिन' कोई भी 'इसके स्थान पर काम नहीं करता है। मुझे बहुत सी नहीं पता है इसलिए मैं उस कोड को बदलने से बचने की कोशिश कर रहा हूं। – brebs

+0

त्वरित अनुवर्ती: मैं इसे बनाने के बारे में कैसे जाउंगा ताकि सी फ़ंक्शन ने पॉइंटर '* n' के रूप में एन लिया और फिर 'm = * n + 1' करके इसे संचालित किया? मेरा वर्तमान कोड विफल रहता है। विशेष रूप से, क्या यह करने के लिए पाइथन कोड में एक त्वरित फिक्स है? – brebs

+0

@brebs: ठीक है, क्षमा करें, 'शून्य *' 'c_void_p' है, लेकिन' शून्य 'सिर्फ' कोई नहीं 'है। वैसे भी, फॉलोअप के लिए, मैं जवाब संपादित कर दूंगा। – abarnert