我正在尝试为Sundials CVODE库编写CFFI包装器。 SWIG对Sundials标题感到窒息,因为它们相互关联,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*))
,但没有取得任何成功。
This question建议采用这种方法:
(cffi:with-foreign-object (p :pointer)
(setf (cffi:mem-ref p :pointer) (cvodecreate 1 2))
(cvodefree p))
这有效(至少它不会引发错误)。我想我理解它是如何工作的:它创建(分配内存)一个指针指向P
,其MEM-REF
(或C语言将解除引用*p
)由CVODECREATE
上的结果填充。最后,我将这个指针传递给指向CVODEFREE
的指针,它正好指望这一点。最后,一旦表单完成,就会释放为P
分配的内存。这是正确的方法吗?它是我唯一可以拿走的吗?
答案 0 :(得分:2)
是的,你的方法看起来正确,这是一个小测试,显示可以直接从repl运行的概念。
(let* (;; a float
(v0 32s0)
;; a pointer to a float foreign memory
(p0 (cffi:foreign-alloc :float :initial-element v0)))
;; a new pointer
(cffi:with-foreign-object (p1 :pointer)
;; make the new pointer point to the first pointer
(setf (cffi:mem-aref p1 :pointer) p0)
;; dereferencing twice should give you the original number
(cffi:mem-aref (cffi:mem-aref p1 :pointer) :float)))
P.S。我相信你现在已经知道了这一点,很抱歉花了这么长时间才得到答案。希望这可以帮助其他人