如何使用Cython将Python列表传递给C函数
我正在使用Raspberry Pi与连接到GPIO的自定义硬件进行交互.控制软件是用
Python编写的,自定义硬件的接口是用C语言编写的,因为它是一个更快的C实现.我现在需要从我的Python开始调用我的C函数,并且最近一直在学习如何在Cython中包装C.除了将Python列表传递给C函数之外,我已经完成了所有工作.
我的自定义硬件需要从1到32个字节发送,因此使用数组. 我在线阅读的Cython教程和其他参考文献都非常简单,不包括如何将列表传递给C,使用numpy,我没有使用,或使用非常复杂的代码示例,缺乏足够的文档供我理解正常. 我现在拥有的是: test.c的 #include <stdio.h> #include "test.h" void pop(void) { a[0] = 0x55; a[1] = 0x66; a[2] = 0x77; a[3] = ' '; } void putAll(int n,char c[]) { memcpy(a,c,n); } char *getAll(void) { return &a[0]; } test.h char a[4]; void putAll(int n,char[]); char *getAll(void); pytest.pyx cimport defns # Populate C array with values def pypop(): defns.pop() # Pass python list to C def pyPutAll(int n,char[:] pyc): cdef char* c = pyc defns.putAll(n,c) # Get array from C def pyGetAll(): cdef char* c = defns.getAll() cdef bytes pyc = c print pyc defns.pxd cdef extern from "test.h": char a[4] void pop() void putAll(int n,char c[]) char *getAll() 使用cython.org中的教程,我的getAll()和pop()函数可以工作,但是当我包含putAll()函数时(取自在链接中找到的process_byte_data示例代码,在Unicode下传递字符串>从Python代码接受字符串) ),我收到此错误: python setup.py build_ext -i Error compiling Cython file: ------------------------------------------------------------ ... def pyputAll(int n,char[:] pyc): ^ ------------------------------------------------------------ pytest.pyx:13:25: Expected an identifier or literal 现在,我有办法解决这个问题 – 将最多32个字节组合成一个int并传递为一个long int,然后在C中将它拉开 – 但它非常难看. 此外,除了使用C实现的库与我的自定义硬件与Python实现的硬件接口之外,我不需要Cython来获得任何性能提升. 任何帮助将不胜感激. (编辑)解决方案 我设法让这个工作.以下是我现在为需要它的人提供的代码. pytest.pyx ... def pyPutAll(int n,c): cdef int *ptr ptr = <int *>malloc(n*cython.sizeof(int)) if ptr is NULL: raise MemoryError() for i in xrange(n): ptr[i] = c[i] defns.putAll(n,ptr) free(ptr) ... test.c的 void putAll(int n,int c[]) { char d[n]; int i; for (i=0;i<n;i++) { d[i] = c[i]; } memcpy(addr,d,n); } 这段代码不是最优的,因为它在python / cython代码中使用了int,然后在C函数中将它转换为char. pytest.pyc中的pyPutAll()函数接受一个普通的python列表.然后它创建一个C指针并分配内存.迭代列表,将每个值放入C数组,最后将指针传递给C函数. 它完成了工作,但我确信其他人可以提供更有效的解决方案. 马特 解决方法ctypes 更适合您要做的事情.
例如:(test.py) from ctypes import create_string_buffer,c_char_p,c_int,CDLL libtest = CDLL("./libtest.so") _putAll = libtest.putAll _putAll.restype = None _putAll.argtypes = [c_int,c_char_p] def putAll(values): """Expects a bytes object,bytearray,or a list of ints.""" char_buffer = create_string_buffer(bytes(values)) _putAll(len(char_buffer),char_buffer) getAll = libtest.getAll getAll.restype = c_char_p getAll.argtypes = None 用法: import test test.putAll(b"hello world") assert test.getAll() == b"hello world" test.putAll(bytearray(b"another string")) test.putAll([1,2,3,255]) 以上是针对python 3的.如果您正在运行python 2,那么您可以将字节替换为str,但该函数的灵活性较低.另外,请注意create_string_buffer创建一个C字符串(在字符串的末尾添加一个额外的NUL字符). 要编译共享库,您需要执行以下操作: gcc -fPIC -g -c -Wall test.c gcc -shared -Wl,-soname,libtest.so.1 -o libtest.so test.o (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |