访问递归Python ctypes结构时出现分段错误
我在使用Python CType访问嵌入到其他结构中的结构中的元素时遇到问题 以下是C:访问递归Python ctypes结构时出现分段错误,python,ctypes,Python,Ctypes,我在使用Python CType访问嵌入到其他结构中的结构中的元素时遇到问题 以下是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; };
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)
我使用的是Python3.4和GCC4.7。这不包括最初调用以触发回调函数的函数或访问共享库的Python代码。我已经验证了所有信息都填充了C中的结构,并且能够在某一时刻用Python打印uuid的内容。当我试图访问hndrange时,我遇到了一个分段错误。我可以在Python中打印hndrange的对象引用,但是如果我试图访问元素,就会出现分段错误
我做错了什么
非常感谢您的帮助。您的
服务
类与gatt\u主要结构不匹配uuid
应该是char
的数组,而不是指针:
class service(ctypes.Structure):
_fields_ = [
('uuid', ctypes.c_char*38),
('changed', ctypes.c_int),
('range', ctypes.POINTER(range))
]
此外,对结构的返回字段使用强制转换也不是一个好主意。查看文档后,您会发现,对于这些类型,将返回相关的python类型。所有其他派生类型都按原样返回
因此,例如ctypes.cast(hndrange.contents.starthnd,ctypes.c_uint16)
将尝试将pythonint
类型转换为ctypes.c_uint16谢谢。我这样做了,但我还是有seg故障。当我试图从range访问其中一个结构元素时,即在以下行出现此错误:starthnd=ctypes.cast(hndrange.contents.starthnd,ctypes.c_uint16)
我可以看到该元素的地址与c代码中的地址匹配。显然,取消对它的引用会导致seg错误。我添加了一些关于您正在进行的转换的信息。我希望这会有帮助。我相信我知道发生了什么,但如果我错了,请纠正我。我一直在尝试从另一个进程访问内存。在Linux(最有可能是OSs)中,进程之间的共享内存通常是不允许的(这是有充分理由的)。因此,我相信实际上是操作系统发出了seg错误,与Python或C实现无关(除了尝试在进程之间共享内存)。@JohnasCukier,前4个cast
操作是不必要的。接下来的两个(starthnd
和endhnd
)不仅是不必要的,而且是错误的,因为您只能强制转换为指针类型。uuid
的最后一次转换是不必要的,并且是由于错误地使用了char*
指针(4或8字节)而不是使用38字节char
数组。如果按照建议使用c_char*38
数组类型,您会发现访问c_char
数组字段会返回一个Python字符串。这里不需要强制转换任何内容。@JohnasCukier,对一个常见的内置函数(如range
)的名称进行阴影处理也是个坏主意。