将PyArrayObject传递给C函数

时间:2018-07-05 09:58:57

标签: c numpy

我尝试编写一个Numpy扩展模块。问题是我不确定如何正确将指向PyArrayObject的指针传递给C函数,这将导致以下行为。考虑下面的代码:

/* File: test_mod.c */

#define NPY_NO_DEPRECATED_API NPY_1_8_API_VERSION
#define PY_ARRAY_UNIQUE_SYMBOL __NP_ARRAY_API

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


static PyObject *
test_mod(PyObject* self, PyObject* args) {

    PyArrayObject* arr;
    if(!PyArg_ParseTuple(args, "O")) {
        printf("Error while parsing objects");
        return NULL;
    }

    /* do some checks 
    ... */

    do_something(&arr);
    return Py_None;
}

/* Method table
... */

/* Module definition structure 
... */

/* Module init function
... */

我想通过引用C函数来传递arr。在上面的片段中,arrPyArrayObject的劣势,后者是C struct。因此,我想出了以下定义:

/* File: test_utilities.c */

#define NPY_NO_DEPRECATED_API NPY_1_8_API_VERSION
#define NO_IMPORT_ARRAY
#define PY_ARRAY_UNIQUE_SYMBOL __NP_ARRAY_API

#include <numpy/arrayobject.h>


void
do_something(struct PyArrayObject **arr) {

    int d = PyArray_NDIM(*arr));
    npy_intp N = PyArray_SIZE(*arr);
    printf("%i, %li", d, N);

}

PyArray_NDIM(PyArrayObject* arr)PyArray_SIZE(PyArrayObject* arr)numpy Array API中的宏。

编译后,该模块会产生预期的输出,但是,伴随一些编译器警告。因此,我怀疑这里一切正常。

test_modul.c的警告:

test_utilities.h:1:25: warning: declaration of 'struct PyArrayObject'
will not be visible outside of this function [-Wvisibility]
void print_array(struct PyArrayObject **arr);
                        ^
test_modul.c:63:14: warning: incompatible pointer types passing 
'PyArrayObject **' (aka 'struct tagPyArrayObject **') to parameter of    
type 'struct PyArrayObject **' [-Wincompatible-pointer-types]
        do_something(&signal);
                    ^~~~~~~
test_utilities.h:1:41: note: passing argument to parameter 'arr' here
void print_array(struct PyArrayObject **arr);

test_utilities.c的警告:

test_utilities.c:10:20: warning: declaration of 'struct PyArrayObject'   
will not be visible outside of this function [-Wvisibility]
do_something(struct PyArrayObject **arr) {
                   ^
test_utilities.c:13:51: warning: incompatible pointer types passing 
'struct PyArrayObject *' to parameter of type 'const PyArrayObject *'   
(aka 'const struct tagPyArrayObject *') [-Wincompatible-pointer-types]
        printf("Array has: %i dimensions.", PyArray_NDIM(*arr));
                                                         ^~~~
/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-
packages/numpy/core/include/numpy/ndarraytypes.h:1464:35: note: passing 
argument to parameter 'arr' here
PyArray_NDIM(const PyArrayObject *arr)
                                  ^
test_utilities.c:16:28: warning: incompatible pointer types passing 
'struct PyArrayObject *' to parameter of type 'PyArrayObject *' (aka  
'struct tagPyArrayObject *') [-Wincompatible-pointer-types]
        npy_intp N = PyArray_SIZE(*arr);
                                  ^~~~
/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site- 
packages/numpy/core/include/numpy/ndarrayobject.h:91:59: note: expanded 
from macro 'PyArray_SIZE' #define PyArray_SIZE(m) 
PyArray_MultiplyList(PyArray_DIMS(m), PyArray_NDIM(m))
                                                   ^
/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-
packages/numpy/core/include/numpy/ndarraytypes.h:1482:29: note: passing 
argument to parameter 'arr' here
PyArray_DIMS(PyArrayObject *arr)
                            ^

我的C语言还不够好,这也许就是为什么我看不到这里发生了什么。 do_something使用指向结构的指针。因此,在做某事时对arr的解引用应该使我从test_mod中的test_mod.c函数指向PyArrayObject结构的原始指针。这是一个误解吗?如果是,为什么会产生预期的结果?

总结一下,如何正确地将PyArrayObject传递给C函数,以便没有警告(关于不兼容的指针类型等)?

1 个答案:

答案 0 :(得分:0)

再次研究文档后,我发现答案非常简单。只需传递struct指针,例如

do_something(arr);

itsef函数应读取

void do_something(PyArrayObject *arr)
{
    int d = PyArray_NDIM(arr));
    npy_intp N = PyArray_SIZE(arr);
    printf("%i, %li", d, N);
}

此外,在C函数没有返回值的情况下,请不要忘记增加Py_None的引用计数。因此,C函数的末尾应显示为

Py_INCREF(Py_None);
return Py_None;

一个人也可以使用内置宏Py_RETURN_NONE,它与以上两行的含义相同。