我正在尝试将共享的C库连接到某些python代码。
与库的接口(interface)类似于

typedef struct{
    int v1;
    double* v2} input;

像这样的其他两种类型:用于配置和输出类型。

我使用ctypes Structure像这样在python中设置了这些结构:
class input(Structure):
    _fields_ = [("v1",c_int),("v2",POINTER(c_double)]

C代码具有一些接收指向该结构的指针的函数,并且argtypes的定义如下:
fun.argtypes = [constraints,input,POINTER(input)]
constraints是另一个结构,带有一些int字段用于配置。

首先,我更新输入结构中的v2字段
input.v2 = generated_array.ctypes.data_as(POINTER(c_double))

然后我称之为:
fun(constraints,input,byref(output))

函数原型(prototype)要求struct和*进行struct(假定输出struct类型与输入struct类型相同)。

然后,我想访问存储在输出的v2字段中的fun的结果。但是我得到了意想不到的结果。有没有更好/正确的方法呢?

我在这里搜索了很多内容,并阅读了文档,但是我找不到问题所在。我没有任何错误消息,但是从共享库收到的警告似乎表明这些接口(interface)上有错误。

我想我已经找到问题了:

当我调用该方法时,会调用一个numpy的complex数组。然后创建4个向量:
    out_real = ascontiguousarray(zeros(din.size,dtype=c_double))
    out_imag = ascontiguousarray(zeros(din.size,dtype=c_double))
    in_real  = ascontiguousarray(din.real,dtype = c_double)
    in_imag  = ascontiguousarray(din.imag,dtype = c_double)

其中din是输入向量。我已经以这种方式测试了该方法:
    print in_real.ctypes.data_as(POINTER(c_double))
    print in_imag.ctypes.data_as(POINTER(c_double))
    print out_real.ctypes.data_as(POINTER(c_double))
    print out_imag.ctypes.data_as(POINTER(c_double))

结果是:
    <model.LP_c_double object at 0x1d81f80>
    <model.LP_c_double object at 0x1d81f80>
    <model.LP_c_double object at 0x1d81f80>
    <model.LP_c_double object at 0x1d81f80>

似乎所有人都指向同一个地方。

经过一些更改后,它可以按预期工作...

经过几次测试,我发现该代码在第一时间几乎是正确的。我一次创建了Structure实例,并更新了它的字段。我改为在每次调用fun时创建一个新实例。我还将所有数组类型都更改为等效的ctypes类型。这似乎使该功能按预期方式工作。

打印行为仍然与上面的测试中一样,但是即使出现这种奇怪的行为,该功能也似乎可以正常工作。 如下面的@ericsun注释所指出的,这是正确的。

最佳答案

struct有一个int字段,该字段可能用于数组长度,尽管我只是在猜测没有完整的函数原型(prototype)。如果确实如此,那么以下示例可能会有所帮助。

首先,我需要在共享库中编译一个测试函数。我将输入数组乘以2:

import os
import numpy as np
from ctypes import *

open('tmp.c', 'w').write('''\
typedef struct {
    int v1; double *v2;
} darray;
int test(darray *input, darray *output) {
    int i;
    /* note: this should first test for compatible size */
    for (i=0; i < input->v1; i++)
        *(output->v2 + i) = *(input->v2 + i) * 2;
    return 0;
}
''')
os.system('gcc -shared -o tmp.so tmp.c')

接下来创建ctypes定义。我添加了一个classmethoddarray制作一个numpy.ndarray:
c_double_p = POINTER(c_double)

class darray(Structure):
    _fields_ = [
      ('v1', c_int),
      ('v2', c_double_p),
    ]
    @classmethod
    def fromnp(cls, a):
        return cls(len(a), a.ctypes.data_as(c_double_p))

lib = CDLL('./tmp.so')
lib.test.argtypes = POINTER(darray), POINTER(darray)

测试:
a1 = np.arange(3) + 1.0
a2 = np.zeros(3)
print 'before:', '\na1 =', a1, '\na2 =', a2

lib.test(darray.fromnp(a1), darray.fromnp(a2))
print 'after:', '\na1 =', a1, '\na2 =', a2

输出:
before:
a1 = [ 1.  2.  3.]
a2 = [ 0.  0.  0.]
after:
a1 = [ 1.  2.  3.]
a2 = [ 2.  4.  6.]

关于python - 具有ctypes函数的Numpy数组接口(interface),我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/15420442/

10-16 10:57