Cython编译错误“Not allowed in a constant expression”

8

The following

cimport cython

@cython.boundscheck(False)
def boundtest():
     cdef int r=4
     cdef double l[3]

这个功能运作正常。但是当我尝试下面的操作时:

cimport cython

@cython.boundscheck(False)
def boundtest():
     cdef int r=4
     cdef double l[r]

我收到了以下错误信息:
[1/1] Cythonizing test.pyx

Error compiling Cython file:
------------------------------------------------------------
...
cimport cython

@cython.boundscheck(False)
def boundtest():
     cdef int r=4
     cdef double l[r]
                   ^
------------------------------------------------------------

test.pyx:13:20: Not allowed in a constant expression
     

由于发现这篇相关的stackexchange帖子和读 Kurt W. Smith 的Cython书籍,所以添加了装饰器。据我所知,这应该可以告诉Cython不必担心由于具有动态索引变量而可能导致的越界错误,但出于某种原因它并没有起作用。我还尝试过更改编译器选项和全局范围内的boundscheck,但都无济于事。
如果不是Cython文档声称已经更新到最新版,我会认为boundscheck已经被弃用了。
1个回答

16

这个失败与cython.boundscheck无关。

边界检查只是检查您是否尝试访问不存在的数组元素。例如,如果您有一个大小为4的数组并尝试访问第5个元素 - 使用 boundscheck(True) 将会导致异常,而使用 boundscheck(False) 将导致未定义行为(可能导致分段错误)。

编译失败的原因是另一个:您不能创建具有动态长度的静态数组!元素的数量需要在编译时确定,这只是一些强制执行的规定(我猜)。

但是,您可以将r定义为在编译时已知:

DEF r=4

cimport cython

@cython.boundscheck(False)
def boundtest():
    cdef double l[r]
你可以直接创建一个NumPy数组并将其存储在一个memoryview变量中:
cimport cython
import numpy as np

@cython.boundscheck(False)
def boundtest():
    cdef int r=4
    cdef double[:] l = np.empty(r, dtype=np.double)

它有效了,非常感谢!我希望链接帖子中的 OP 更明确地更改他的代码以使用 memoryview 变量。 - Takoda
@Takoda Cython结合了Python和C,因此需要对两者都有一定的了解才能正确使用。可能只是“假设”您不会使用cdef double l[r]创建动态长度数组,而只能使用已知常量,例如cdef double l[4] - MSeifert
1
很奇怪Cython不支持C99的可变长度数组,但这对他们来说是好事。可变长度数组是危险的。 - Alex Huszagh

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接