我有一个yec.c文件定义了一个具有两个函数的结构:
结构 MEC </跨度> { 年龄; int数;};
static PyObject * nopoint(PyObject * self,PyObject *args ){ 结构 MEC </跨度> 米; int n1,n2;
if(!PyArg_ParseTuple(args,“ii”,&amp; n1,&amp; n2)) 返回NULL;
printf(“nopoint(c)nombres:%d et%d!\ n”,n1,n2);
m.age = n1; m.number = n2
你需要使用 ctypes.addressof 来自Python脚本,而不是 ctypes.byref (这是与C指针不同的对象),然后,在 yec.c ,将输入值解析为 long (要么 int 如果在32位)并将其分配给“struct mec *”。
ctypes.addressof
ctypes.byref
yec.c
long
int
见下面一个工作示例:
#include <python2.7/Python.h> struct mec { int age; int number; }; static PyObject* nopoint(PyObject* self, PyObject* args) { struct mec m; int n1, n2; if (!PyArg_ParseTuple(args, "ii", &n1, &n2)) return NULL; printf("nopoint(c) nombres: %d et %d!\n", n1, n2); m.age = n1; m.number = n2; printf("nopoint(c) age nb: %d et %d!\n", m.age, m.number); return Py_BuildValue("i", n1 + n2); } static PyObject* viapoint(PyObject* self, PyObject* args) { struct mec *m; if (!PyArg_ParseTuple(args, "l", &m)) return NULL; printf("viapoint av(c) age nb: %d et %d!\n", m->age, m->number); m->age = 10; m->number = 1; printf("viapoint ap(c) age nb: %d et %d!\n", m->age, m->number); return Py_BuildValue("i", m->age + m->number); } static PyMethodDef MyYecMethods[] = { {"nopoint", nopoint, METH_VARARGS, "Description de fune"}, {"viapoint", viapoint, METH_VARARGS, "Description de fdeux"}, {NULL, NULL, 0, NULL} }; PyMODINIT_FUNC inityec(void) { (void) Py_InitModule("yec", MyYecMethods); }
在Python中:
from ctypes import * import yec class Mec(Structure): _fields_ = [ ("age", c_int), ("number", c_int)] m = Mec(1, 2) print "py mec class", m.age, m.number yec.viapoint(addressof(m))
运行它,我得到:
> python run.py py mec class 1 2 viapoint av(c) age nb: 1 et 2! viapoint ap(c) age nb: 10 et 1!
你可以解析 Structure 作为读写缓冲区( "w#" )。通过将其作为参数传递,您可以放心,它是一个引用的对象。它还确保传入的缓冲区是正确大小的可写内存。崩溃的Python是不可接受的。你应该在Python中获得异常。如果你有Python代码使得解释器的段错误变得微不足道,那你就错了。
Structure
"w#"
static PyObject* viapoint(PyObject* self, PyObject* args) { struct mec *m; size_t size; if (!PyArg_ParseTuple(args, "w#", &m, &size)) return NULL; if (size != sizeof(struct mec)) { PyErr_SetString(PyExc_TypeError, "wrong buffer size"); return NULL; } printf("viapoint av(c) age nb: %d et %d!\n", m->age, m->number); m->age = 10; m->number = 1; return Py_BuildValue("i", m->age + m->number); }
蟒蛇:
from ctypes import * import yec class Mec(Structure): _fields_ = [ ("age", c_int), ("number", c_int), ] class Bad(Structure): _fields_ = [ ("age", c_int), ("number", c_int), ("extra", c_int), ] m = Mec(1, 2) print yec.viapoint(m) # TypeError b = Bad(1, 2, 3) print yec.viapoint(b)
如果你只是接受一个地址作为参数,你的函数可能会对无效指针进行段错误,或者只是返回垃圾或修改内存,这会使你的程序在以后以一种难以理解的方式崩溃。此外,通过解析地址,您需要有条件地定义是否解析为 long 要么 long long 在预处理器中,取决于的大小 void * 相比 long 。例如,在Win64上 long 是32位并将指针解析为 long 截断它。最后,需要您首先调用的API addressof 在Python中是一种低效的kludge。
long long
void *
addressof