0

我正在学习用 cython 包装的 C 库。我使用 cython 编译了几个简单的 C 函数和头文件,现在尝试运行另一个示例,该示例比以前的示例更复杂。

我下载了 Sundials C 源代码的第一个版本(仅限 IDA 模块)并使用 VS 2019 制作了一个 *.lib。现在我试图只包装一个函数来看看它是如何工作的。但是我不知道如何正确地将带有 void * 参数的函数包装到 cython 函数。这是示例。

是指向 C函数ida_mem分配的内存地址的 void 指针。malloc我应该如何IDACalcIC使用正确的指针参数调用底部的函数?

IDA.pyx 文件


cdef extern from "ida.h":
    
    ctypedef double real;
    ctypedef int integer;
    int IDACalcIC(void *ida_mem, int icopt, real tout1, real epicfac, int maxnh, int maxnj, int maxnit, int lsoff, real steptol)

            
cpdef CyIDACalcIC(void *ida_mem, icopt, tout1, epicfac, maxnh, maxnj, maxnit, lsoff, steptol):
    
    cdef int icopt
    cdef int maxnh
    cdef int maxnj
    cdef int maxnit
    cdef int lsoff
    cdef real tout1
    cdef real epicfac
    cdef real steptol
    
    IDACalcIC(ida_mem (?), icopt,  tout1,  epicfac, maxnh,  maxnj,  maxnit, lsoff, steptol)
4

1 回答 1

0

您传递的 void 指针只是求解器的工作内存,您需要在调用可能使用它的其他函数(通常是求解函数)之前自行分配它。这在您自己管理内存的 C 中很典型,但在 Python 中则非常陌生。

您正在寻找在 pySundials 中执行此代码的 Cython 等效项(第 94-105 和 147-153 行)

您可以通过调用 IDACreate 自己分配内存,然后将返回的值传递给 IDACalcIC,尽管我建议使用类似于下面的包装类来执行此操作,这将使 python 用户感觉更自然地使用 C 库。

该类的IdaMemObj存在是为了包装由 C 函数IDACreate以 a 形式返回的分配的内存void *。它用于__del__确保在 python 对象超出范围并被垃圾收集时释放(释放)分配的内存。

# PySUNDIALS: trunk/2.5.0/src/ida.py lines 94-105
class IdaMemObj(object):
    def __init__(self, obj):
        self.obj = obj
        self.dealloc = False

    def __del__(self):
        if self.dealloc:
            p = ctypes.c_void_p()
            p.value = self.obj
            ida.IDAFree(ctypes.byref(p))
ida.IDAFree.argtypes = [ctypes.POINTER(ctypes.c_void_p)]
ida.IDAFree.restype = None
# PySUNDIALS: trunk/2.5.0/src/ida.py lines 147-153
def IDACreate():
    obj = ida.IDACreate()
    if obj == None:
        raise AssertionError("SUNDIALS ERROR: IDACreate() failed - returned NULL pointer")
    return IdaMemObj(obj)
ida.IDACreate.argtypes = []
ida.IDACreate.restype = ctypes.c_void_p
于 2020-09-25T09:45:23.597 回答