Перенос макросов заголовков C с помощью Cython - PullRequest
1 голос
/ 06 мая 2020

Я пишу оболочку Cython для библиотеки NAG C.

В одном из файлов заголовков библиотеки NAG C есть макросы:

#define NAG_FREE(x) x04bdc((Pointer *)&(x))

Указатель is void *

x04bd c is:

extern void NAG_CALL x04bdc(Pointer *ptr);

NAG_FREE - это эквивалент библиотеки NAG функции free () для освобождения памяти.

Вот отрывок из моего файла lib_nag_integrate.pxd:

cdef extern from "<nagx04.h>":
    void x04bdc(Pointer *ptr)

x04bd c - это «модная» бесплатная (mallo c) процедура. Я не могу получить доступ к этому коду.

Затем я создаю функцию cdef в моем файле .pyx:

cdef void NAG_FREE(double *x):
    x04bdc(<Pointer *>&x)

Здесь я ввел тип, приведенный x к двойному указателю, так как это то, что я пытается освободить память, однако примеры библиотеки NAG, похоже, используют ее для любого типа указателя.

При запуске сценария python, который вызывает функцию cpdef, которая в конечном итоге использует NAG_FREE, я получаю следующую ошибку:

Process finished with exit code 134 (interrupted by signal 6: SIGABRT)

Если я закомментирую вызовы NAG_FREE, он работает нормально, однако NAG говорит, что необходимо использовать NAG_FREE.

Функция cdef, использующая NAG_FREE:

cdef (double,double,Integer,Integer) dim1_fin_gen(lib_nag_integrate.NAG_D01SJC_FUN objfun,double a, double b,double epsabs, double epsrel,
                         Integer max_num_subint,Nag_User *comm,integration_out *output):
    """

    :param f: user function
    :type f: function
    :param a: lower limit of integration
    :type a: real float
    :param b: upper limit of integration
    :type b: real float
    :param epsabs: user requested absolute error
    :type epsabs: integer
    :param epsrel: user requested relative error
    :type epsrel: integer
    :param max_num_subint: maximum number of subintervals
    :type max_num_subint: real integer
    :return: integration value of user function f
    :rtype: real float
    """

    cdef lib_nag_integrate.Nag_QuadProgress _qp
    cdef lib_nag_integrate.NagError _fail
    cdef double result
    cdef double abserr


    _fail.print = True
    _fail.code = 0
    _fail.errnum = 0
    _fail.handler = NULL

    lib_nag_integrate.d01sjc(objfun, a, b, epsabs, epsrel,
                             max_num_subint, &result, &abserr,
                    &_qp, comm, &_fail)
    if _fail.code > 0 :
        errorMessage = _fail.message
        raise NagException(_fail.code,errorMessage)
        print(_fail.message)

    else:
        output[0].result = result
        output[0].abserr = abserr
        output[0].fun_count = _qp.fun_count
        output[0].num_subint = _qp.num_subint

        NAG_FREE(_qp.sub_int_beg_pts)
        NAG_FREE(_qp.sub_int_end_pts)
        NAG_FREE(_qp.sub_int_result)
        NAG_FREE(_qp.sub_int_error)

Мой заголовочный файл libnag_integrate.pxd импортирует из библиотеки c следующее:

cdef extern from "<nag_types.h>":
    ctypedef bint Nag_Boolean
    ctypedef long Integer
    ctypedef void* Pointer
    ctypedef struct NagError:
        int code
        bint print "print"
        char message[512]
        Integer errnum
        void (*handler)(char*,int,char*)
    ctypedef struct Nag_User:
        Pointer p
    ctypedef struct Nag_QuadProgress:
        Integer num_subint
        Integer fun_count
        double *sub_int_beg_pts
        double *sub_int_end_pts
        double *sub_int_result
        double *sub_int_error

cdef extern from "<nagx04.h>":
    (void*) NAG_ALLOC "x04bjc" (size_t size)
    void x04bdc(Pointer *ptr)


cdef extern from "<nagd01.h>":
    void d01sjc(NAG_D01SJC_FUN f, double a, double b,
         double epsabs, double epsrel, Integer max_num_subint, double *result,
         double *abserr, Nag_QuadProgress *qp, Nag_User *comm,
         NagError *fail)

d01sj c - это процедура интеграции, к которой я не могу получить доступ. Он выделяет память qp.sub_int_beg_pts et c внутри.

Я думаю, что у меня поврежденный указатель, вызывающий ошибку. Если да, то где это и как исправить?

большое спасибо

При дальнейшем осмотре структуры _qp. Та же ошибка возникает при разыменовании, например:

x = _qp.sub_int_end_pts[0]

, поэтому разыменование _qp вызывает ошибку.

Тип структуры Nag_QuadProgress импортируется из файла заголовка NAG в мой .pxd следующим образом:

cdef extern from "<nag_types.h>":
ctypedef struct Nag_QuadProgress:
        Integer num_subint
        Integer fun_count
        double *sub_int_beg_pts
        double *sub_int_end_pts
        double *sub_int_result
        double *sub_int_error

Есть идеи, почему разыменование указателей в этой структуре вызывает ошибку?

1 Ответ

0 голосов
/ 06 мая 2020

С точки зрения Cython вы используете NAG_FREE как функцию, поэтому вы должны объявить это как. На самом деле не имеет значения, что это настоящий макрос, и определенно не помогает попытаться его реализовать.

cdef extern from "whatever_the_nag_header_is":
    void NAG_FREE(Pointer x)
    # or
    void NAG_FREE(void *x)
    # or
    void NAG_FREE(...)  # accepts anything - Cython doesn't attempt to match types

Возможно, вам придется немного поиграть с тип аргументов, чтобы заставить его работать - я предложил три варианта.

На самом деле все, что вы хотите сделать, это предоставить Cython достаточно информации, чтобы он мог сгенерировать правильный код C, и справа C код - NAG_FREE(your_variable), как если бы это вызов функции.


С вашим кодом:

  • (<integration_out*>output)[0] предполагает, что вы делаете что-то очень не так. output - это указатель integration_out, так зачем вы его приводите? Он либо ничего не делает, либо вызывает потенциальную ошибку.

  • Несмотря на то, что вы заявляете, что возвращает кортеж типа C, вы на самом деле ничего не возвращаете.

...