Common Lisp CFFI: pointer to pointer

I am trying to write a CFFI wrapper for CVODE Gallery Sundials . SWIG was choking on the Sundials headers, as they are quite interconnected, and SWIG was unable to find the correct headers, so I did it manually: a little complicated, but I succeeded.

Now I'm trying to check if it works correctly. For now, just create a "problem object" and delete it. This is where the problem begins. Thus, the "problem object" is allocated through the function

SUNDIALS_EXPORT void *CVodeCreate(int lmm, int iter); 

Why did I create a wrapper:

 (cffi:defcfun "CVodeCreate" :pointer (lmm :int) (iter :int)) 

PS. SUNDIALS_EXPORT (at least on Unix) is basically nothing.

Now, to destroy an object, Sundials uses its own function:

 SUNDIALS_EXPORT void CVodeFree(void **cvode_mem); 

So, I need to pass a reference to the object created by CVodeCreate . In C, if my memory is not to blame, I would do something like CVodeFree(&problem_object) . In CL, I wrote this shell for a function:

 (cffi:defcfun "CVodeFree" :void (cvode-mem :pointer)) 

So here COVDE-MEM is a pointer to a pointer. The question is how to get the pointer of a pointer in CL / CFFI? Here is the beginning of the code:

 (defvar *p* (cvodecreate 1 2)) 

(PS. Do not worry about the numbers passed to CVodeCreate , they just tell you which methods to use, you still need to define constants to make it more readable)

So *P* something like

 #.(SB-SYS:INT-SAP #X7FFFE0007060) 

If I pass it directly to CVODEFREE , it will CVODEFREE :

 CL-USER> (cvodefree *p*) ; Evaluation aborted on #<SIMPLE-ERROR "bus error at #X~X" {1005EC9BD3}>. 

I tried to skip (CFFI:POINTER-ADDRESS *P*) , but this leads to a similar "bus error ..." (not even sure if this function returns what I need). I also tried to do (CFFI:MAKE-POINTER (CFFI:POINTER-ADDRESS *P*)) , again without success.

This question offers this approach:

 (cffi:with-foreign-object (p :pointer) (setf (cffi:mem-ref p :pointer) (cvodecreate 1 2)) (cvodefree p)) 

This works (at least it does not cause an error). I think I understand how this works: it creates (allocates memory for) a pointer to a pointer P whose MEM-REF (or in terms of C will be dereferenced *p ) is populated with the result on CVodeCreate . Finally, I pass this pointer to a pointer to a CVODEFREE that expects just that. Finally, the memory allocated for P is freed upon completion of the form. Is this the right approach? And is this the only one I can accept?

+5
source share
1 answer

Yup, your approach looks right, here is a small test to show a concept that can be run directly from 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 I'm sure you already knew this, it is a pity that it took you so long to answer. Hope this helps other people.

+2
source

Source: https://habr.com/ru/post/1244568/


All Articles