Common Lisp CFFI:指向指针的指针
Common Lisp CFFI: pointer to the pointer
我正在尝试为 Sundials CVODE 库编写 CFFI 包装器。 SWIG 在日晷 headers 上感到窒息,因为它们相互关联,而 SWIG 找不到合适的 headers,所以我手工完成了:有点费力,但我做到了。
现在我正在尝试测试它是否正常工作。现在,只需简单地创建 "problem object" 并删除它。这就是问题的开始。因此,"problem object" 是通过函数
分配的
SUNDIALS_EXPORT void *CVodeCreate(int lmm, int iter);
我为此创建了包装器:
(cffi:defcfun "CVodeCreate" :pointer
(lmm :int)
(iter :int))
PS。 SUNDIALS_EXPORT
(至少在 Unix 上)基本上没什么。
现在,要销毁 object,日晷使用它自己的函数:
SUNDIALS_EXPORT void CVodeFree(void **cvode_mem);
因此,我需要将对 CVodeCreate
创建的 object 的引用传递给它。在 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*)
但结果类似 "bus error..." (甚至不确定这个函数 returns 是否是我需要的)。我也尝试过 (CFFI:MAKE-POINTER (CFFI:POINTER-ADDRESS *P*))
,但还是没有成功。
建议采用这种方法:
(cffi:with-foreign-object (p :pointer)
(setf (cffi:mem-ref p :pointer) (cvodecreate 1 2))
(cvodefree p))
这有效(至少它不会引发错误)。我想我理解它是如何工作的:它创建(分配内存)一个 pointer-to-a-pointer P
,它的 MEM-REF
(或者在 C 术语中将取消引用 *p
)被填充根据 CVODECREATE
上的结果。最后,我将此 pointer-to-a-pointer 传递给 CVODEFREE
,它正是期望如此。最后,表单完成后,分配给 P
的内存将被释放。这是正确的方法吗?这是我唯一能接受的吗?
是的,你的方法看起来不错,这里有一个小测试来展示可以运行直接来自 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。我相信你现在已经知道了,很抱歉花了这么长时间才给你答复。希望这可以帮助其他人
我正在尝试为 Sundials CVODE 库编写 CFFI 包装器。 SWIG 在日晷 headers 上感到窒息,因为它们相互关联,而 SWIG 找不到合适的 headers,所以我手工完成了:有点费力,但我做到了。
现在我正在尝试测试它是否正常工作。现在,只需简单地创建 "problem object" 并删除它。这就是问题的开始。因此,"problem object" 是通过函数
分配的SUNDIALS_EXPORT void *CVodeCreate(int lmm, int iter);
我为此创建了包装器:
(cffi:defcfun "CVodeCreate" :pointer
(lmm :int)
(iter :int))
PS。 SUNDIALS_EXPORT
(至少在 Unix 上)基本上没什么。
现在,要销毁 object,日晷使用它自己的函数:
SUNDIALS_EXPORT void CVodeFree(void **cvode_mem);
因此,我需要将对 CVodeCreate
创建的 object 的引用传递给它。在 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*)
但结果类似 "bus error..." (甚至不确定这个函数 returns 是否是我需要的)。我也尝试过 (CFFI:MAKE-POINTER (CFFI:POINTER-ADDRESS *P*))
,但还是没有成功。
(cffi:with-foreign-object (p :pointer)
(setf (cffi:mem-ref p :pointer) (cvodecreate 1 2))
(cvodefree p))
这有效(至少它不会引发错误)。我想我理解它是如何工作的:它创建(分配内存)一个 pointer-to-a-pointer P
,它的 MEM-REF
(或者在 C 术语中将取消引用 *p
)被填充根据 CVODECREATE
上的结果。最后,我将此 pointer-to-a-pointer 传递给 CVODEFREE
,它正是期望如此。最后,表单完成后,分配给 P
的内存将被释放。这是正确的方法吗?这是我唯一能接受的吗?
是的,你的方法看起来不错,这里有一个小测试来展示可以运行直接来自 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。我相信你现在已经知道了,很抱歉花了这么长时间才给你答复。希望这可以帮助其他人