简体   繁体   English

用 Cython 包装 C header 宏

[英]Wrapping C header macros with Cython

I am writing a Cython wrapper for the NAG C library.我正在为 NAG C 库编写 Cython 包装器。

In one of the header files from the NAG C library is the macros:在 NAG C 库中的 header 文件之一是宏:

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

Pointer is void*指针无效*

x04bdc is: x04bdc 是:

extern void NAG_CALL x04bdc(Pointer *ptr);

NAG_FREE is the NAG library equivalent of free(), to free up memory. NAG_FREE 是相当于 free() 的 NAG 库,用于释放 memory。

Here is the extract from my lib_nag_integrate.pxd file:这是我的 lib_nag_integrate.pxd 文件的摘录:

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

x04bdc is a "fancy" free (malloc) routine. x04bdc 是一个“花哨的”免费 (malloc) 例程。 I cant access this code.我无法访问此代码。

I then create a cdef function in my.pyx file:然后我在 my.pyx 文件中创建一个 cdef function :

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

Here i have type casted x to a double pointer, as that is what I am trying to free from memory, however the NAG library examples seem to use it for any type of pointer.在这里,我将 x 类型转换为双指针,因为这是我试图从 memory 中释放出来的,但是 NAG 库示例似乎将它用于任何类型的指针。

When running the python script which calls a cpdef function which eventually uses NAG_FREE, I get the following error:当运行 python 脚本调用最终使用 NAG_FREE 的 cpdef function 时,我收到以下错误:

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

If i comment out the NAG_FREE calls then it works fine, however NAG say it is necessary to use NAG_FREE.如果我注释掉 NAG_FREE 调用,那么它工作正常,但是 NAG 说有必要使用 NAG_FREE。

The cdef function using NAG_FREE is:使用 NAG_FREE 的 cdef function 是:

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)

My libnag_integrate.pxd header file imports the following from the c library:我的 libnag_integrate.pxd header 文件从 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)

d01sjc is an integration routine which I cannot access. d01sjc 是我无法访问的集成例程。 It allocates the memory of qp.sub_int_beg_pts etc inside.它在里面分配qp.sub_int_beg_pts等的memory。

I think I have a corrupt pointer causing the error.我想我有一个损坏的指针导致错误。 If so, where is it and how to I fix it?如果是这样,它在哪里以及如何修复它?

many thanks非常感谢

Upon further inspection of the structure '_qp'.进一步检查结构“_qp”。 The same error occurs when dereferencing eg:取消引用时会发生相同的错误,例如:

x = _qp.sub_int_end_pts[0]

so its the dereferencing of _qp which is causing the error.所以它是导致错误的 _qp 的取消引用。

The struct type Nag_QuadProgress is imported from its NAG header file into my.pxd as follows:结构类型 Nag_QuadProgress 从其 NAG header 文件导入到 my.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

Any ideas why dereferencing the pointers in this structure causes the error?任何想法为什么取消引用此结构中的指针会导致错误?

From Cython's point of view you're using NAG_FREE as a function, so that's what you should declare it as.从 Cython 的角度来看,您将NAG_FREE用作 function,因此您应该将其声明为。 It doesn't really matter that it's a really macro, and it certainly doesn't help to attempt to reimplement it.它是一个真正的宏并不重要,尝试重新实现它当然也无济于事。

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

You may have to play around a bit with the type of the arguments to get it to work - I've suggested three options.您可能需要尝试使用 arguments 的类型才能使其工作 - 我建议了三个选项。

Really all you're aiming to do is to give Cython enough information that it can generate the right C code, and the right C code is NAG_FREE(your_variable) , as if it's a function call.实际上,您要做的就是为 Cython 提供足够的信息,使其可以生成正确的 C 代码,而正确的 C 代码是NAG_FREE(your_variable) ,就好像它是 ZC1C425268E17A98 调用一样。


With your code:使用您的代码:

  • (<integration_out*>output)[0] suggests you're doing something very wrong. (<integration_out*>output)[0]表明你做错了什么。 output is an integration_out pointer so why are you casting it? output一个integration_out指针,那么你为什么要转换它呢? It either does nothing or introduces a potential error.它要么什么都不做,要么引入一个潜在的错误。

  • Despite claiming to return a C tuple type you actually don't bother to return anything.尽管声称返回 C 元组类型,但您实际上并不费心返回任何东西。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM