5

我正在尝试为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最后,一旦表单完成,分配的内存就会被释放。这是正确的方法吗?它是我唯一可以带走的吗?

4

1 回答 1

4

是的,你的方法看起来不错,这里有一个小测试来展示可以直接从 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)))

ps 我相信你现在已经知道了,抱歉这么久才给你答复。希望这可以帮助其他人

于 2016-07-26T15:07:56.827 回答