如何使用ctypes将Python列表转换为C数组?

63
如果我有以下两个代码集,如何将它们粘合在一起?
void
c_function(void *ptr) {
    int i;

    for (i = 0; i < 10; i++) {
        printf("%p", ptr[i]);
    }

    return;
}


def python_routine(y):
    x = []
    for e in y:
        x.append(e)
我该如何使用一个连续的 x 元素列表来调用 c_function?我尝试将 x 强制转换为 c_void_p,但这并没有起作用。我还尝试使用类似于下面的东西:
x = c_void_p * 10 
for e in y:
    x[i] = e
但这会得到一个语法错误。 C 代码明显需要数组的地址。我该如何让它发生呢?
4个回答

116
以下代码适用于任意列表:
import ctypes
py_values = [1, 2, 3, 4]
arr = (ctypes.c_int * len(py_values))(*py_values)

在Python中,“*pyarr”是什么意思? - AaronYC
5
@AaronYC 对于混淆感到抱歉;pyarr 是一个普通的 Python 列表,就像 pyar = [1,2,3,4]。如果你想知道名字前面的星号是什么意思,请查看这个链接:https://dev59.com/PnRC5IYBdhLWcg3wJNcN - Gabi Purcaru
4
回答不错,但对于我们这些外行人来说有点轻率。 - Jiminion
1
@Jiminion 请看下面我的回答,其中有语法的解释。 - akhan
2
非常好,现在我们该如何释放那个 arr 变量呢?我们肯定不必在这里使用 C 语言中的 free() 函数,对吧? - Sergiy Kolodyazhnyy
显示剩余2条评论

24

这是对被接受答案的解释。

ctypes.c_int * len(pyarr) 创建了一个长度为4、类型为c_int 的数组(序列) (Python 3Python 2)。由于c_int是一个构造函数需要一个参数的对象,因此(ctypes.c_int * len(pyarr)(*pyarr)pyarr一次性初始化每个c_int实例。一个更易读的形式是:

pyarr = [1, 2, 3, 4]
seq = ctypes.c_int * len(pyarr)
arr = seq(*pyarr)

使用type函数查看seqarr之间的区别。


13

来自ctypes教程:

>>> IntArray5 = c_int * 5
>>> ia = IntArray5(5, 1, 7, 33, 99)

1
尝试创建超过255个项的数组。 - Pavel Patrin
4
适用于超过255个项目:IntArray300 = c_int * 300; arrayWith300Elements=IntArray300(*list([i for i in range(300)])) - Guillaume Jacquenot

2
import ctypes
import typing

def foo(aqs : typing.List[int]) -> ctypes.Array:
    array_type = ctypes.c_int64 * len(aqs)
    ans = array_type(*aqs)
    return ans

for el in foo([1,2,3]):
    print(el)

这将会得到:
1
2
3

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接