我想要包装的库的头文件中有以下宏:
#define RB_ROOT (struct rb_root) { NULL, }
RB_ROOT宏似乎用于在C代码中使用NULL初始化根节点。这就是rb_root
的样子:
struct rb_root {
struct rb_node *rb_node;
};
我想在Cython中初始化一个rb_root。这意味着我需要创建它并将其设置为NULL。
我试过了
self.root = ckerneltree.rb_root(node=NULL)
但这给了我错误
cdef ckerneltree.rb_root root
cdef ckerneltree.rb_node node
def __cinit__(self):
self.root = ckerneltree.rb_root(node=NULL)
^
------------------------------------------------------------
kerneltree.pyx:10:45: Cannot assign type 'void *' to 'rb_node'
如果我像这样删除kwarg
self.root = ckerneltree.rb_root()
我收到一个令人讨厌的C编译器警告:
kerneltree.c: In function '__pyx_tp_new_10kerneltree_IntervalTree':
kerneltree.c:1100:22: warning: '__pyx_t_1.rb_node' may be used uninitialized in this function [-Wmaybe-uninitialized]
__pyx_v_self->root = __pyx_t_1;
^
kerneltree.c:1090:18: note: '__pyx_t_1.rb_node' was declared here
struct rb_root __pyx_t_1;
^
这样做的正确方法是什么?
聚苯乙烯。这就是我的.pxd的样子:
cdef extern from "src/rbtree.h":
cdef struct rb_node:
pass
cdef struct rb_root:
rb_node node
我的.pyx:
cimport ckerneltree
cdef class IntervalTree:
cdef ckerneltree.rb_root root
def __cinit__(self):
self.root = ckerneltree.rb_root()
答案 0 :(得分:2)
这可能会令人惊讶,但在您的情况下,self.rb_root.node
已设置为NULL
。但是,如果要将其明确设置为NULL
,则可以执行以下操作:
cdef class IntervalTree:
cdef ckerneltree.rb_root root
def __cinit__(self):
self.root.rb_root = NULL # setting pointer to NULL explicitly
对于Python编码器而言,这可能是违反直觉的,其中所有内容都是引用,但root
不是指向rb_root
- 对象的指针,而是对象本身。这就是cdef类IntervalTree
在C代码中的定义:
struct __pyx_obj_4test_IntervalTree {
PyObject_HEAD
struct rb_root root;
};
如您所见,它被定义为rb_root
而非rb_root *
。 IntervalTree
- 对象的内存布局非常简单:
+-------------------+ +--------------------+
| PyObject | | rb_root |
+-------------------+ +--------------------+
| Py-Obect members | | rb_node |
+-------------------+ +--------------------+
| ?? bytes | | 8 bytes |
+-------------------+ +--------------------+
Python对象的默认初始化在执行__cinit()__
之前启动,并将对象的整个内存设置为0
s,因此rb_node
的8个字节(这是一个指向rb_node
- 对象的指针的值为0
,与NULL
相同。但是明确地初始化它没有任何害处。