如何在Python中操作C函数返回的C类型指针?
这是在"Testlib.c"里的C代码。我只是从C函数返回一个指向结构体的指针。所有的C代码会被编译成一个库,以便被Python调用。
#include <stdio.h>
#include <stdlib.h>
typedef struct{
int num;
char c;
}aStruct;
aStruct* newStructPointer()
{
aStruct* s = (aStruct*)malloc(sizeof(aStruct)) ;
s->num = 3;
s->c = 'f';
return s;
}
int getNumField(aStruct* a)
{
return a->num;
}
char getCharField(aStruct* a)
{
return a->c;
}
这是Python代码。它非常简单,调用newStructPointer来获取一个新的结构体,然后获取它字段中的数字值。
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from ctypes import *
class testlib(object):
def __init__(self):
lib=cdll.LoadLibrary("libtestdylib.dylib")
s=lib.newStructPointer()
num=lib.getNumField(cast(s, c_void_p))
t=testlib()
然后,它崩溃了,因为指针已经无效了,这里是崩溃报告:
Thread 0 Crashed:: Dispatch queue: com.apple.main-thread
0 libtestdylib.dylib 0x000000010638ef5c getNumField + 12 (interface.c:26)
1 libffi.dylib 0x00007fff9354ef9c ffi_call_unix64 + 76
2 libffi.dylib 0x00007fff9354f78e ffi_call + 790
3 _ctypes.so 0x000000010637390e _ctypes_callproc + 794
4 _ctypes.so 0x000000010636df80 0x10636b000 + 12160
5 org.python.python 0x0000000106085f72 PyObject_Call + 101
6 org.python.python 0x00000001060ffdf5 PyEval_EvalFrameEx + 15416
7 org.python.python 0x00000001060fc093 PyEval_EvalCodeEx + 1641
8 org.python.python 0x00000001060a3796 0x10607c000 + 161686
9 org.python.python 0x0000000106085f72 PyObject_Call + 101
10 org.python.python 0x00000001060909a7 0x10607c000 + 84391
11 org.python.python 0x0000000106085f72 PyObject_Call + 101
12 org.python.python 0x00000001060cb6ce 0x10607c000 + 325326
13 org.python.python 0x00000001060c7184 0x10607c000 + 307588
14 org.python.python 0x0000000106085f72 PyObject_Call + 101
15 org.python.python 0x00000001060ffdf5 PyEval_EvalFrameEx + 15416
16 org.python.python 0x00000001060fc093 PyEval_EvalCodeEx + 1641
17 org.python.python 0x00000001060fba24 PyEval_EvalCode + 54
18 org.python.python 0x000000010611ac2c 0x10607c000 + 650284
19 org.python.python 0x000000010611acd3 PyRun_FileExFlags + 137
20 org.python.python 0x000000010611a821 PyRun_SimpleFileExFlags + 718
21 org.python.python 0x000000010612b363 Py_Main + 2995
22 libdyld.dylib 0x00007fff8e4215fd start + 1
我已经阅读了Python的文档,地址是 https://docs.python.org/2/library/ctypes.html ,但没有找到任何有用的信息。我该如何解决这个问题呢?
1 个回答
4
你需要正确地定义函数的原型,这样才能安全地调用这些函数:
# define your structure
class aStruct(ctypes.Structure):
_fields_ = [('num', ctypes.c_int),
('c', ctypes.c_char]
# this defines aStructPtr to be a pointer
# to an aStruct
aStructPtr = ctypes.POINTER(aStruct)
# next, define the interface to your functions:
lib.newStructPointer.restype = aStructPtr
lib.newStructPointer.argtypes = [] # void, no arguments
# your getter functions both take the structure pointer as inputs
# and return an integer or char
lib.getNumField.restype = ctypes.c_int
lib.getNumField.argtypes = [aStructPtr]
lib.getCharField.restype = ctypes.c_char
lib.getCharField.argtypes = [aStructPtr]
注意,如果你在ctypes中正确声明了结构体,就不需要使用C语言的获取函数了。下面的代码也应该可以正常工作:
s = lib.newStructPointer()
num_value = s.contents.num
char_value = s.contents.c