问题描述
我有这个功能:
def test(unsigned int N):
cdef int *my_arr = <int *> malloc(N * sizeof(int))
cdef int[:] new_arr = <int[:N]>my_arr
free(my_arr)
当我将它放在一个名为 test.pyx 的单独文件上时,编译它并从 CPython 的解释器中调用它,它工作正常。我这样称呼它:
import test
test.test(10)
当我将此函数添加到现有库(在具有多个文件和依赖项的大项目中)时,问题就来了,它编译得很好,但是当我调用它时会抛出一个错误:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "av/video/frame.pyx", line 37, in av.video.frame.test
cdef int[:] new_arr = <int[:N]>my_arr
ValueError
如您所见,它特别抱怨这一行:
cdef int[:] new_arr = <int[:N]>my_arr
两种情况下的函数完全一样,而且我传递了相同的N值,真的很奇怪。
有谁知道在哪种情况下可以简单地强制int *
转换来int[:]
抛出 ValueError?
语境
我正在尝试向 PyAV 库添加一些功能,因此我将该功能添加到此文件中:
https://github.com/PyAV-Org/PyAV/blob/main/av/video/frame.pyx
当我这样称呼它时它会抛出:
import av
av.video.frame.test(10)
我在 MacOS 10.15.7 上,使用 Python 3.7.7 和 Cython 0.29.21 和 Clang 11.0.3 编译器。
更新 1
我已经检查了 Cython 为该test()
函数生成的 C 代码,两种情况下都是相同的,这是为有问题的行生成的代码:
/* "av/video/frame.pyx":37
* def test(unsigned int N):
* cdef int *my_arr = <int *> malloc(N * sizeof(int))
* cdef int[:] new_arr = <int[:N]>my_arr # <<<<<<<<<<<<<<
* free(my_arr)
*
*/
if (!__pyx_v_my_arr) {
PyErr_SetString(PyExc_ValueError,"Cannot create cython.array from NULL pointer");
__PYX_ERR(0, 37, __pyx_L1_error)
}
__pyx_t_3 = __pyx_format_from_typeinfo(&__Pyx_TypeInfo_int); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 37, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_3);
__pyx_t_2 = Py_BuildValue((char*) "(" __PYX_BUILD_PY_SSIZE_T ")", ((Py_ssize_t)__pyx_v_N)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 37, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_2);
__pyx_t_1 = __pyx_array_new(__pyx_t_2, sizeof(int), PyBytes_AS_STRING(__pyx_t_3), (char *) "c", (char *) __pyx_v_my_arr);
if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 37, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_1);
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
__pyx_t_4 = __Pyx_PyObject_to_MemoryviewSlice_ds_int(((PyObject *)__pyx_t_1), PyBUF_WRITABLE); if (unlikely(!__pyx_t_4.memview)) __PYX_ERR(0, 37, __pyx_L1_error)
__Pyx_DECREF(((PyObject *)__pyx_t_1)); __pyx_t_1 = 0;
__pyx_v_new_arr = __pyx_t_4;
__pyx_t_4.memview = NULL;
__pyx_t_4.data = NULL;
所以我开始用调用注释行,__PYX_ERR()
发现引发 ValueError 的行是这样的:
__pyx_t_4 = __Pyx_PyObject_to_MemoryviewSlice_ds_int(((PyObject *)__pyx_t_1), PyBUF_WRITABLE); if (unlikely(!__pyx_t_4.memview)) __PYX_ERR(0, 37, __pyx_L1_error)
这一行更新了__Pyx_memviewslice
之前声明的 a:
__Pyx_memviewslice __pyx_t_4 = { 0, 0, { 0 }, { 0 }, { 0 } };
这个函数很可能会设置错误:
__Pyx_PyObject_to_MemoryviewSlice_ds_int()
所以也许演员(PyObject *)__pyx_t_1
做错了什么或者__pyx_t_1
不是它所期望的。
但我真的不知道这一切是如何工作的,所以也许还有其他原因导致这种行为,比如一些编译器标志?