【问题标题】:Cython compiling error: Saying that Array is a StructCython 编译错误:说 Array 是 Struct
【发布时间】:2019-08-16 03:24:22
【问题描述】:

这是我的 Cython 错误的最低可重现版本。代码在 C++ 中运行。

编译器告诉我错误 C2088 “+= 对于结构是非法的”。但是,它正在传递一个数组。

pyx 文件:

from libc.stdint cimport uint32_t as Card
from cpython cimport array
import array

cdef extern from "ace_eval.h":
    void ACE_addcard(h, Card c)

def create_hand():
    cdef array.array h = array.array('I',[0, 0, 0, 0, 0])
    ACE_addcard(h, 257)

    return h

从头部导入的函数是:

#define ACE_addcard(h,c)  h[c&7]+=c,h[3]|=c 

我也尝试过使用声明我的数组 cdef Card h[5]

【问题讨论】:

    标签: cython cythonize


    【解决方案1】:

    array.array 是一个 Python 对象,它最终被编译成一个结构体(所以这就是 C++ 所看到的)。对它的元素访问由 __getitem____setitem__ 在 Python 级别控制,它们由 Cython 编译为 C API 函数调用。当 Cython 看到正在操作的数组的代码时,它将生成适当的 C API 函数调用。您使用 C++ #define 语句编写代码试图在 C++ 编译时对其进行操作,并阻止 Cython 知道发生了什么。

    理想情况下,您应该使用“typed memoryviews”,它可以让 Cython 更快地访问数组(但仍然不适用于 C++ #define,因为这是在 Cython 处理文件之后应用的) :

    cdef int[::1] h = array.array('I',[0, 0, 0, 0, 0]) # you may have to change the type long... I haven't tested it
    
    h[257&7]+=257
    h[3]|=257 
    

    如果您绝对坚持使用宏,那么他们需要使用 C++ 数组接口。指针可能是最简单的选择,可以从以下位置获取:

    cdef int* h_ptr = &h[0]
    

    【讨论】:

    • 谢谢。我今晚会试试看。我想我需要改变我的想法,从仅仅连接到 C 到将更多代码放在 Cython 中。你认为这是一个很好的通用方法吗?
    • 如果可以的话,我绝对会 100% 避免将宏和 Cython 混合使用——这会造成混淆。如果代码已经存在并且有用,则连接到 C 没有问题 - 这确实意味着您必须在“指针级别”使用 Cython,这消除了 Pythony 的一些不错的优势
    • 第一种方法奏效了。第二种方法没有。我仍然无法在 Cython 中生成一个数组并发送到 C 以供在那里使用。能够这样做会很好 - 我想在 C 中保留一些更复杂的函数。这些函数也将数组作为输入。
    【解决方案2】:

    @DavidW 的第二种方式

        cdef Card h[5]
        h[:] = [0, 0, 0, 0, 0]
        cdef Card* h_ptr = &h[0]
    

    一旦我也像这样调整我的 cdef 以接受指针,它也可以工作。请注意,#define 宏中的函数没有更改,也没有指定返回类型。

    cdef extern from "ace_eval.h":
           void ACE_addcard(Card* h, Card c)
    

    这让我可以完美地传递我的任何数组。

    这实际上是它在文档中所说的,但对我来说有点迟钝 - 希望我的解释对其他人有所帮助。 https://cython.readthedocs.io/en/latest/src/userguide/external_C_code.html

    如果头文件使用宏定义函数,请将其声明为普通函数,并带有适当的参数和结果类型。

    【讨论】:

    • 如果您不指定参数类型,则假定它是 Python 对象(array.array 是,但指针不是)。另一种选择是使用 C varargs 语法 void ACE_addcard(...) 在这种情况下 Cython 不会尝试检查参数类型(然后由 C 来查看它是否编译)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-22
    • 1970-01-01
    • 2017-09-22
    • 2018-04-25
    相关资源
    最近更新 更多