我无法使用Python ctypes访问嵌入在其他结构中的结构中的元素。
这是C:
struct GSList
{
void* data;
GSList* next;
};
struct att_range
{
uint16_t start;
uint16_t end;
};
struct gatt_primary
{
char uuid[38];
int changed;
struct att_range* range;
};
typedef void( *python_callback_t )( GSList* services );
static python_callback_t pycb = NULL;
// pycb is set to a valid function pointer before the callback below is called.
static void primary_all_cb( GSList *services, uint8_t status )
{
if( status == 0 ) {
pycb( services );
}
}
这是Python:
import ctypes
# CDLL is used to access a shared library that contains the C code above
class range(ctypes.Structure):
_fields_ = [
('starthnd', ctypes.c_uint16),
('endhnd', ctypes.c_uint16)
]
class service(ctypes.Structure):
_fields_ = [
('uuid', ctypes.c_char_p),
('changed', ctypes.c_int),
('range', ctypes.POINTER(range))
]
class servicelist(ctypes.Structure):
pass
servicelist._fields_ = [
('data', ctypes.POINTER(service)),
('next', ctypes.POINTER(servicelist))
]
CB_FUNC_TYPE = ctypes.CFUNCTYPE(None, ctypes.POINTER(servicelist))
def cb(csvclist):
svclist = ctypes.cast(csvclist, ctypes.POINTER(servicelist))
data = ctypes.cast(svclist.contents.data, ctypes.POINTER(service))
next = ctypes.cast(svclist.contents.next, ctypes.POINTER(servicelist))
hndrange = ctypes.cast(data.contents.range, ctypes.POINTER(range))
starthnd = ctypes.cast(hndrange.contents.starthnd, ctypes.c_uint16)
endhnd = ctypes.cast(hndrange.contents.endhnd.contents, ctypes.c_uint16)
uuid = ctypes.cast(data.contents.uuid, ctypes.c_char_p)
print('start: 0x%X, end: 0x%X, uuid: %s' % (starthnd, endhnd, uuid))
cb_func = CB_FUNC_TYPE(cb)
// gatt is the shared library. ble_start source is not shown here, but it sets the callback function pointer.
gatt.ble_start(cb_func)
我正在使用Python 3.4和gcc 4.7。这不包括最初调用以触发回调函数的函数或用于访问共享库的Python代码。我已经验证了所有信息都填充了C中的结构,并且能够在某一点上用Python打印uuid的内容。当我尝试访问hndrange时出现分段错误。我可以在Python中打印出hndrange的对象引用,但是如果我尝试访问这些元素,我会遇到分段错误。
我做错了什么?
感谢任何帮助。
答案 0 :(得分:1)
您的service
课程与gatt_primary
结构不匹配。 uuid
应该是char
的数组,而不是指针:
class service(ctypes.Structure):
_fields_ = [
('uuid', ctypes.c_char*38),
('changed', ctypes.c_int),
('range', ctypes.POINTER(range))
]
除此之外,对结构的返回字段使用强制转换也不是一个好主意。查看Structures and unions文档,您会发现,fundamental data types返回了相关的python类型。所有其他派生类型都按原样返回。
因此,例如ctypes.cast(hndrange.contents.starthnd, ctypes.c_uint16)
会尝试将python int
类型转换为ctypes.c_uint16
。