cython 将 void* 转换回 Python 对象

0 投票
1 回答
4949 浏览
提问于 2025-04-18 09:00

在尝试把 void* 转换回 Python 对象时遇到了错误信息。

根据这篇文章 将 Python 对象转换为 C 的 void 类型,这个转换应该是很简单的。

struct _node {
    void * data;
} node;

cpdef match(self, path):
    m = cpyr3.r3_tree_match(self.root, path, NULL)

    if m:
        return <object>m.data

错误信息:

Error compiling Cython file:
------------------------------------------------------------
...

    cpdef match(self, path):
        m = cpyr3.r3_tree_match(self.root, path, NULL)

        if m:
            return <object>m.data
                           ^
------------------------------------------------------------

cpyr3.pyx:18:28: Cannot convert 'node *' to Python object

我测试了几种方法:

1.

Error compiling Cython file:
------------------------------------------------------------
...
        cpyr3.r3_tree_compile(self.root, NULL)

    cpdef match(self, path):
        m = cpyr3.r3_tree_match(self.root, path, NULL)
        if m:
            return <object>(m.data[0])
                            ^
------------------------------------------------------------

cpyr3.pyx:17:29: Cannot convert 'node *' to Python object

2.

这个方法可以通过编译,但在运行时会抛出异常。

Traceback (most recent call last):
  File "test.py", line 22, in <module>
    print run(r)
  File "test.py", line 13, in run
    return r.match('/foo/bar')
  File "cpyr3.pyx", line 14, in pyr3.R3Tree.match (cpyr3.c:1243)
    cpdef match(self, path):
  File "cpyr3.pyx", line 17, in pyr3.R3Tree.match (cpyr3.c:1186)
    return <object>(m[0].data[0])
AttributeError: 'dict' object has no attribute 'data'

这个字典是从哪里来的?

编辑2:重现问题(详细信息):

源代码库: https://github.com/lucemia/pyr3/tree/cython

git clone https://github.com/lucemia/pyr3/ -b cython 
cd pyr3
rm cpyr3.c
rm pyr3.c
git submodule init; git submodule update; 
cd r3
./autogen.sh
./configure
cd ..
python setup_cython.py build_ext --inplace

编辑3:

将 cpyr3.pxd 文件中的内容从

cdef extern from "r3.h":
    ctypedef struct node:
        pass

改为

cdef extern from "r3.h":
    ctypedef struct node:
        void *data

这样就解决了问题!

1 个回答

2

我测试了

cdef struct _node:
    void * data
ctypedef _node node

cpdef pack_unpack():
    cdef node my_node = node(<void *>"some object")

    # This is what should be returned
    cdef node *m = &my_node
    return <object>m.data

import pyximport
pyximport.install()

import c_unpacker
print(c_unpacker.pack_unpack())

结果完全没问题。

所以我认为可能是其他地方出了问题。如果能提供一个简单的可运行示例让我测试一下,那就更好了。

这里有三个可能的错误需要检查:

  • m 没有类型或者类型不正确

  • self.rootpath 类型不对

  • _node 类型不对。例如,使用 cdef struct _node: pass 时,我得到的结果是

    Error compiling Cython file:
    ------------------------------------------------------------
    ...
    cpdef pack_unpack():
        cdef node my_node = node(<void *>"some object")
    
        # This is what should be returned
        cdef node *m = &my_node
        return <object>m.data
                       ^
    ------------------------------------------------------------
    
    c_unpacker.pyx:10:20: Cannot convert 'node *' to Python object
    

    这是因为 m 根据 Cython 看到的错误定义没有 data 这个属性。在这种情况下,Cython 默认会将其转换为 Python 类型。


在编译的过程中,我发现你有

cdef extern from "r3.h":
    ctypedef struct node:
        pass

这是我列表上的第三点。你应该把它改成

cdef extern from "r3.h":
    ctypedef struct node:
        void *data

这样就能消除那个错误。

撰写回答