指针类型与 PyArray_SimpleNew 不匹配
Pointer-type mismatch with PyArray_SimpleNew
我正在使用 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 forbids conversion of object pointer to function pointer type
所以,显然,出于某种原因,PyArrayObject
s 应该是函数指针。
根据文档(例如,here),PyArray_SimpleNew
有一个 PyObject *
类型的 return,因此上面的内容应该完全没问题。此外,我没有收到与其他功能类似的警告 returning PyObject *
.
现在,虽然这只是我们正在讨论的警告,而且我使用 PyArray_SimpleNew
的程序按预期工作,但所有这些都表明 Numpy C API 没有像我认为的那样工作(或有错误)。所以我想了解这背后的原因。
我在以下系统上生成了以上内容:
- 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
而改变。
为了回答您为什么会收到有关 "ISO C forbids conversion of object pointer to function pointer type" 的警告的问题,我检查了 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]
在第 807、810 和 812 行的 numpy/__multiarray_api.h
中 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?
我正在使用 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 forbids conversion of object pointer to function pointer type
所以,显然,出于某种原因,PyArrayObject
s 应该是函数指针。
根据文档(例如,here),PyArray_SimpleNew
有一个 PyObject *
类型的 return,因此上面的内容应该完全没问题。此外,我没有收到与其他功能类似的警告 returning PyObject *
.
现在,虽然这只是我们正在讨论的警告,而且我使用 PyArray_SimpleNew
的程序按预期工作,但所有这些都表明 Numpy C API 没有像我认为的那样工作(或有错误)。所以我想了解这背后的原因。
我在以下系统上生成了以上内容:
- 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
而改变。
为了回答您为什么会收到有关 "ISO C forbids conversion of object pointer to function pointer type" 的警告的问题,我检查了 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]
在第 807、810 和 812 行的 numpy/__multiarray_api.h
中 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?