【发布时间】:2013-03-03 11:04:22
【问题描述】:
我正在尝试将共享 C 库与一些 python 代码接口。 与库的接口类似于
typedef struct{
int v1;
double* v2} input;
还有两种类似的类型:用于配置和输出类型。
我在 python 中使用ctypes Structures 像这样设置这些结构:
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))
函数原型要求 struct 和 * 到 struct(假设输出 struct 类型与输入 struct 类型相同)。
然后我想访问存储在输出的 v2 字段中的 fun 的结果。但我得到了意想不到的结果。有更好/正确的方法吗?
我在这里搜索了很多并阅读了文档,但我找不到问题所在。我没有任何错误消息,但我从共享库收到的警告似乎表明这些接口存在错误。
我想我发现了问题:
当我调用该方法时,会调用一个复杂的 numpy 数组。然后我创建了 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 评论所指出的那样是正确的。
【问题讨论】:
-
请贴出完整代码,c代码是做什么的?
-
很遗憾我不能分享完整的代码,因为它是 nda 下的第三方库。但这只是一种科学算法,它接受两个向量并返回其他 2 个向量。如果没有完整的描述,您是否认为问题不清楚?
-
c函数接口不清楚,
fun.argtypes = [...,POINTER(input)]和fun(..,input,byref(output))不是同一个接口。 -
我明白了。我会更新以说明清楚。
-
关于
LP_c_double对象,这是 Python 对象地址,而不是指针中的地址。您只打印了一个临时指针对象;在下一次打印时,它已经被释放并且相同的地址被重新使用。查看contents属性,或者只是[0]索引。