我正在尝试为Sundials CVODE库编写 CFFI 包装器。SWIG 对日晷标头感到窒息,因为它们相互关联,而 SWIG 找不到合适的标头,所以我手工完成:有点费力,但我已经做到了。
现在我正在尝试测试它是否正常工作。现在,只需简单地创建“问题对象”并删除它。这就是问题开始的地方。因此,“问题对象”是通过函数分配的
SUNDIALS_EXPORT void *CVodeCreate(int lmm, int iter);
我为此创建了包装器:
(cffi:defcfun "CVodeCreate" :pointer
(lmm :int)
(iter :int))
PS。SUNDIALS_EXPORT
(至少在 Unix 上)基本上什么都不是。
现在,为了销毁对象,Sundials 使用了它自己的函数:
SUNDIALS_EXPORT void CVodeFree(void **cvode_mem);
所以,我需要将它的引用传递给由CVodeCreate
. 在 C 中,如果我的记忆没有问题,我会做类似CVodeFree(&problem_object)
. 在 CL 中,我为函数编写了这个包装器:
(cffi:defcfun "CVodeFree" :void
(cvode-mem :pointer))
所以,这里COVDE-MEM
有一个指向指针的指针。问题是如何获取 CL/CFFI 中指针的指针?这是代码的开头:
(defvar *p* (cvodecreate 1 2))
(PS。不用担心传递给 的数字CVODECREATE
,它们只是告诉使用哪些方法,仍然需要定义常量以使其更具可读性)
所以*P*
是这样的
#.(SB-SYS:INT-SAP #X7FFFE0007060)
如果我直接将它传递给CVODEFREE
,它最终会出错:
CL-USER> (cvodefree *p*)
; Evaluation aborted on #<SIMPLE-ERROR "bus error at #X~X" {1005EC9BD3}>.
我试过传递,(CFFI:POINTER-ADDRESS *P*)
但它会导致类似的“总线错误......”(甚至不确定这个函数是否返回我需要的东西)。我也尝试过(CFFI:MAKE-POINTER (CFFI:POINTER-ADDRESS *P*))
,再次没有任何成功。
这个问题提出了这种方法:
(cffi:with-foreign-object (p :pointer)
(setf (cffi:mem-ref p :pointer) (cvodecreate 1 2))
(cvodefree p))
这有效(至少它不会引发错误)。我想我理解它是如何工作的:它创建(分配内存)一个指向指针的指针P
,其MEM-REF
(或用 C 术语将是取消引用*p
)由 on 的结果填充CVODECREATE
。最后,我将这个指向指针的指针传递给CVODEFREE
,这正是预期的。P
最后,一旦表单完成,分配的内存就会被释放。这是正确的方法吗?它是我唯一可以带走的吗?