指针类型与PyArray_SimpleNew不匹配

时间:2015-03-10 12:08:16

标签: c pointers numpy compiler-warnings python-c-api

我正在使用C API为Numpy创建一个Python模块,并且遇到与PyArray_SimpleNew输出的奇怪不兼容性,我想了解。但首先是一个最小的例子:

# include <Python.h>
# include <numpy/arrayobject.h>

void foo()
{
    Py_Initialize();
    import_array();

    npy_intp dims[1] = {42};
    PyObject * A = PyArray_SimpleNew(1,dims,NPY_DOUBLE); // Line A

    Py_Finalize();
}

int main()
{
    foo();
    return 0;
}

如果我用gcc source.c -lpython2.7 -I/usr/include/python2.7 --pedantic编译它,我得到(引用A行):

  

ISO C禁止将对象指针转换为函数指针类型

所以,显然,PyArrayObject s由于某种原因预计会成为函数指针。


根据文档(例如,here),PyArray_SimpleNew返回PyObject *类型,因此上述内容应该完全没问题。此外,我没有得到与其他函数返回PyObject *类似的警告。

现在,虽然这只是我们正在谈论的一个警告,并且我使用PyArray_SimpleNew的程序按预期工作,但所有这些都表明Numpy C API无法正常工作(或者有bug) 。因此,我想了解这背后的原因。


我在以下系统中制作了以上内容:

  • GCC 4.7.2(Debian 4.7.2-5),Numpy 1.6.2
  • GCC 4.8.2(Ubuntu 4.8.2-19ubuntu1),Numpy 1.8.2

在这两种情况下,情况都会随# define NPY_NO_DEPRECATED_API NPY_1_8_API_VERSION而变化。

1 个答案:

答案 0 :(得分:3)

为了回答你为什么收到关于“ISO C禁止将对象指针转换为函数指针类型”的警告的问题,我检查了numpy的源代码。

PyArray_SimpleNew是第125行numpy/ndarrayobject.h中定义的宏:

#define PyArray_SimpleNew(nd, dims, typenum) \
        PyArray_New(&PyArray_Type, nd, dims, typenum, NULL, NULL, 0, 0, NULL)

将A行扩展为:

PyObject * A = PyArray_New(&PyArray_Type, 1, dims, typenum, NULL, NULL, 0, 0, NULL); // Line A

PyArray_New本身就是第1017行numpy/__multiarray_api.h中定义的宏:

#define PyArray_New \
        (*(PyObject * (*)(PyTypeObject *, int, npy_intp *, int, npy_intp *, void *, int, int, PyObject *)) \
         PyArray_API[93])

将A行扩展为:

PyObject * A = (*(PyObject * (*)(PyTypeObject *, int, npy_intp *, int, npy_intp *, void *, int, int, PyObject *))
                PyArray_API[93])(&PyArray_Type, 1, dims, typenum, NULL, NULL, 0, 0, NULL); // Line A

这个复杂的表达式可以简化为:

// PyObject * function93(PyTypeObject *, int, npy_intp *, int, npy_intp *, void *, int, int, PyObject *)
typedef PyObject * (*function93)(PyTypeObject *, int, npy_intp *, int, npy_intp *, void *, int, int, PyObject *);

// Get the PyArray API function #93, cast the function pointer to its
// signature, and call it with the arguments to `PyArray_New`.
PyObject * A = (*(function93) PyArray_API[93])(&PyArray_Type, 1, dims, typenum, NULL, NULL, 0, 0, NULL); // Line A

导致禁止转换的部分是:

*(function93) PyArray_API[93]

numpy/__multiarray_api.h行807,810和812 PyArray_API上 声明为void **。所以PyArray_API[93]void *(即一个对象 指针)被转换为函数指针。

我对NumPy或它的C-api并不熟悉,但它看起来像你 正确使用它。 NumPy碰巧使用了一些非标准的,未定义的 GCC支持的内部行为,但ISO标准没有(即NumPy不能通过ISO标准移植)。

另见[SciPy-User] NumPy C API: where does casting pointer-to-object to pointer-to-function come from?