appeler c depuis python avec ctypes: passer des vecteurs

Je veux appeler la fonction ac de python en utilisant ctypes. Dans la documentation, je ne comprends pas comment passer du pointeur aux vecteurs. La fonction que je veux appeler est:

double f(int n, double* x) { int i; double p=1; for (i=0; i< n; i ++) p = p * x[i]; return p; } 

J’ai modifié la fonction avec le pointeur vide, il devient donc f(int, void*) avec une dissortingbution interne à doubler. Je fais ce qui suit:

 def f(x): n = len(x) libc = '/path/to/lib.so' cn = c_int(n) px = pointer(x) cx = c_void_p(px) libc.restype = c_double L = libc.f(cn, cx) return L 

Je suppose que x est un tableau numpy, mais je ne suis pas sûr de savoir comment les tableaux numpy sont organisés dans la mémoire et si c’est la meilleure solution.


Modifier:

Aucune des méthodes proposées ne fonctionne avec mon tableau numpy, c’est peut-être dû à la façon dont je définis le tableau:

 x = np.array([], 'float64') f = open(file,'r') for line in f: x = np.append(x,float(line)) 

mais certains d’entre eux fonctionnent si j’ai une liste explicite comme [1,2,3,4,5] , plutôt qu’une liste qui a été définie ailleurs et qui est référencée comme x

Basé sur la réponse de @Sven Marnach :

 #!/usr/bin/env python import ctypes import numpy as np from numpy.ctypeslib import ndpointer libf = ctypes.cdll.LoadLibrary('/path/to/lib.so') libf.f.restype = ctypes.c_double libf.f.argtypes = [ctypes.c_int, ndpointer(ctypes.c_double)] def f(a): return libf.f(a.size, np.ascontiguousarray(a, np.float64)) if __name__=="__main__": # slice to create non-contiguous array a = np.arange(1, 7, dtype=np.float64)[::2] assert not a.flags['C_CONTIGUOUS'] print(a) print(np.multiply.reduce(a)) print(f(a)) 

Sortie

 [ 1. 3. 5.] 15.0 15.0 

Supprimer l’appel np.ascontiguousarray() produit un résultat incorrect ( 6.0 sur ma machine).

Vous pouvez l’appeler comme ça:

 #!python from ctypes import * #!python from ctypes import * # double f(int n, double* x) f = CDLL('/path/to/lib.so').f f.argtypes = [c_int, POINTER(c_double)] f.restype = c_double if __name__ == '__main__': array = (c_double * 5)(1, 2, 3, 4, 5) r = f(len(array), array) print(r) 

Si vous avez un tableau numpy, vous pouvez utiliser numpy.array.ctypes.data_as :

 #!python from ctypes import * import numpy # double f(int n, double* x) f = CDLL('/path/to/lib.so').f f.argtypes = [c_int, POINTER(c_double)] f.restype = c_double if __name__ == '__main__': array = numpy.array([1, 2, 3, 4, 5]) r = f(array.size, array.astype(numpy.double).ctypes.data_as(POINTER(c_double))) print(r) 

ou:

 #!python from ctypes import * import numpy # double f(int n, double* x) f = CDLL('/path/to/lib.so').f f.argtypes = [c_int, POINTER(c_double)] f.restype = c_double if __name__ == '__main__': array = numpy.double([1, 2, 3, 4, 5]) r = f(array.size, array.ctypes.data_as(POINTER(c_double))) print(r) 

apparemment j’avais besoin de spécifier le drapeau contigous pour le faire fonctionner

http://scipy-lectures.github.io/advanced/interfacing_with_c/interfacing_with_c.html

c’est un extrait de mon code:

 array_1d_double = numpy.ctypeslib.ndpointer(dtype=numpy.double, ndim=1, flags='CONTIGUOUS') libc.f.argtypes = [c_int, array_1d_double] libc.f(n, x)