Common Lisp CFFI:指向指针的指针

时间:2016-03-07 10:48:11

标签: pointers common-lisp cffi

我正在尝试为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分配的内存。这是正确的方法吗?它是我唯一可以拿走的吗?

1 个答案:

答案 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。我相信你现在已经知道了这一点,很抱歉花了这么长时间才得到答案。希望这可以帮助其他人