在ctypes中使用指向自定义CNode数组的指针报错,如何修复?
问题描述
定义的ctypes树结构:
from ctypes import Structure, c_int32, POINTER class CNode(Structure): pass CNode._fields_ = [ ("type", c_int32), ("children", POINTER(CNode)), ]
转换Python树到CNode树的函数:
def gen_c_tree(tree): cnode = gen_c_node(tree) if len(tree.children) > 0: tmp = [gen_c_node(child) for child in tree.children] cnode.children = POINTER(CNode * len(tree.children))(*tmp) return cnode
运行时触发错误:
Traceback (most recent call last): File "<frozen runpy>", line 198, in _run_module_as_main File "<frozen runpy>", line 88, in _run_code File "path/file", line 32, in <module> genctree.gen_c_tree(parser.tree) File "path/file", line 29, in gen_c_tree cnode.children = POINTER(CNode * len(tree.children))(*tmp) ^^^^^^^^^^^^^^ TypeError: incompatible types, LP_CNode_Array_1 instance instead of LP_CNode instance
修复方案
错误原因
POINTER(CNode * len(tree.children))(*tmp) 创建的是指向CNode数组类型的指针(比如LP_CNode_Array_1),但CNode的children字段定义的是指向单个CNode的指针(LP_CNode),二者类型不兼容。
修改后的代码
from ctypes import cast, POINTER def gen_c_tree(tree): cnode = gen_c_node(tree) if len(tree.children) > 0: tmp = [gen_c_node(child) for child in tree.children] # 创建对应长度的CNode数组类型 CNodeArrayType = CNode * len(tmp) # 用子节点初始化数组 children_array = CNodeArrayType(*tmp) # 将数组转换为指向CNode的指针(对应C语言中数组名转指针的行为) cnode.children = cast(children_array, POINTER(CNode)) # 关键:保存数组的引用,避免Python垃圾回收销毁数组导致野指针 cnode._children_array = children_array return cnode
关键说明
- 类型转换:用
cast把CNode数组转换成POINTER(CNode),匹配字段定义的类型,这对应C语言里数组隐式转为首元素指针的行为。 - 引用保留:必须把
children_array绑定到cnode的属性上(比如_children_array),否则Python的垃圾回收会在函数结束后销毁数组,导致C端访问到无效内存。
内容的提问来源于stack exchange,提问作者Amol Borkar
相关产品推荐
相关产品推荐

