如何在cython中将结构初始化为NULL?

时间:2018-04-30 09:53:07

标签: cython

我想要包装的库的头文件中有以下宏:

#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()

1 个答案:

答案 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相同。但是明确地初始化它没有任何害处。