python - Access data at memory address with ctypes -
i trying create python wrapper old c program takes inputs pointers. @ point, can program run cannot figure out how values @ designated pointers.
this simplified c script:
#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;}
and simplified python code:
from ctypes import * import sys libc = cdll("src/program.so") class context(structure): _fields_ = [ ("wts", pointer(c_double)), //tried see if 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()
i have tried commands print tmp[1].wts[1]
, print tmp[2]
prints memory address , not value (or incredibly small values incorrect 2.15880221124e-314). able return list of values of wts.
your c function returns void
, not context *
. so, code casting random uninitialized memory context *
, , trying deref it.
on top of that, if did return context
object reference, tmp[1]
try deref memory after object, still garbage.
when try interpret random memory double, you're going segfaults or values 2.15880221124e-314
if you're lucky—if you're unlucky, you'll correct-looking still random values 0.0
.
meanwhile, since c function modifies arguments in place, don't need fancy here. use variables passed in.
so:
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]
this works, , prints out 1.0
.
and if c function did return array of context
structs matching ctypes
declaration, work fine. example:
#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); (int i=0; i!=4; ++i) { double *wtsses = malloc(sizeof(double) * 5); (int j=0; j!=4; ++j) { wtsses[j] = + j; } context context = { wtsses, *res, *kks, m, *ex }; contexts[i] = context; } return contexts; }
compile this, run existing python script added print tmp[1].wts[1]
, , print out 2.0
.
finally, followup, first let's change c code take int *n
, *n
input:
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;}
now, call python, have create c_int
, pass pointer it. since you're doing first half (which wasn't necessary before—just set argtypes
instead… but it's necessary now, convenient), it's one-line change:
libc.cprogram(wts, res, kks, pointer(n), ex)
this works if n
in-out parameter.
but really, don't need see pointer object @ python; thing you're doing creating pass function, letting collected. pass c pointer without creating ctypes pointer object (which again works if n
in-out parameter), use byref
:
libc.cprogram(wts, res, kks, byref(n), ex)
Comments
Post a Comment