用ctypes从python中调用c:传递向量

时间:2014-03-24 16:36:44

标签: python c arrays numpy ctypes

我想使用ctypes从python调用c函数。 从documentation我不明白如何将指针传递给向量。我要调用的函数是:

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

我已经使用void指针修改了函数,因此它变为f(int, void*),内部强制转换为double。我做了以下事情:

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

我假设x是一个numpy数组,但我不确定numpy数组是如何在内存中组织的,如果这是最好的解决方案。


编辑:

所提议的方法都不适用于我的numpy数组,可能是因为我定义了数组:

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

但是如果我有一个像[1,2,3,4,5]这样的明确列表,而不是在其他地方定义的列表,那么它们中的一部分可以工作,它被称为x

3 个答案:

答案 0 :(得分:2)

基于@Sven Marnach's answer

#!/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))

输出

[ 1.  3.  5.]
15.0
15.0

删除np.ascontiguousarray()调用会产生错误的结果(我的计算机上为6.0)。

答案 1 :(得分:1)

您可以这样称呼它:

#!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)

如果你有numpy数组,你可以使用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)

或:

#!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)

答案 2 :(得分:-2)

显然我需要指定连续的标志才能使其正常工作

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

这是我的代码摘录:

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)