Передача PyArrayObject в функцию C - PullRequest
0 голосов
/ 05 июля 2018

Я пытаюсь написать модуль расширения 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
... */

Я хочу передать arr по ссылке на функцию C. В приведенном выше фрагменте arr - это указатель на PyArrayObject, который является 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)
                            ^

Я (пока) не так хорош в Си, и, вероятно, поэтому я не вижу, что здесь происходит. do_something принимает указатель на структуру. Следовательно, разыменование arr в чем-либо должно дать мне исходный указатель на структуру PyArrayObject из функции test_mod в test_mod.c. Это неправильное представление, и если да, то почему это дает ожидаемые результаты?

Чтобы подвести итог, как правильно передать PyArrayObject в функцию C, чтобы не было предупреждений (относительно несовместимых типов указателей и т. Д.)?

1 Ответ

0 голосов
/ 12 июля 2018

После повторного изучения документов я нашел ответ очень простым. Нужно просто передать указатель структуры, как

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);
}

Кроме того, не следует забывать увеличить счетчик ссылок на Py_None в случаях, когда функция C не имеет возвращаемого значения. Следовательно, конец функции C должен читать

Py_INCREF(Py_None);
return Py_None;

Можно также использовать встроенный макрос Py_RETURN_NONE, который имеет то же значение, что и две вышеупомянутые строки.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...