Note: These notes were written by Grotler, a Lisp hacker that can sometimes be spotted on the Lisp Discord server. Lifted from those silo'd halls, they're published here with Grotler's permission. I've found them quite useful as a reference, maybe others will too.
Is this how one makes an array in SBCL to send to C ?
(setf tmp1 (sb-alien:make-alien (sb-alien:array sb-alien:int 10)))
Disclaimer: I'm using CFFI most of the time; so this is knowledge from general dealing with C libraries & reading SBCL manual.
Manual section: https://www.sbcl.org/manual/#Introduction-to-the-Foreign-Function-Interface
One thing to notice is that this would always make a fixed sized array. You could pass the optional size argument to make-alien and element-type as the type, and create an array like that:
(sb-alien:make-alien sb-alien:int N) ;; => returns pointer to an array of 10 integers.
Note however, that it would also mean that the type of this pointer will not contain information about array size: types
(alien (* (signed 32))
vs
(alien (* (array (signed 32) 10)))
That also means that in the second case you will need to call defer on the result to get the pointer to the array.
Another thing to keep in mind is that unless foreign code frees that array, you'd need to call free yourself; like this:
(let ((array (sb-alien:make-alien sb-alien:int N)))
(unwind-protect
(foreign-funcall ...)
(sb-alien:free-alien array)))
Note that not freeing it will lead to memory leaks; and freeing it twice will probably crash SBCL into LDB.
Third thing is that instead of allocating the array on the heap (if it is small
enough, of course), you might want to stack-allocate it instead – that is, use
with-alien. Important thing is that it only creates a foreign object with
dynamic extent (unlike let which allows you to return the value bound with
it). Another difference from make-alien is that these variables do not contain
pointers to foreign objects but are already deferred:
(sb-alien:with-alien ((arr (array sb-alien:int 10))) (type-of arr)) ; => (ALIEN (ARRAY (SIGNED 32) 10))
Also note that you can't create an array of variable size (and you can't pass size here, as it is replace by initial-value in bindings).
One more thing is that you might want to have a lisp-array and a foreign-array to share the same data.
This could be done via two different methods – both that I know of involve CFFI.
CFFI has a somewhat experimental interface for "Shareable Vectors". They are
created via (cffi:make-shareable-byte-vector N), and when you need to pin down
this array and get a pointer – you need to pin it down so that garbage
collector doesn't move it while a foreign function is trying to modify / access
it – you use with-pointer-to-vector-data:
(cffi:with-pointer-to-vector-data (ptr vec) call foreign function here)
It is still important to note that such vectors can be moved – so the array
should not be "stored" & accessed later by the foreign code after the call to it
returns. (Just like with with-alien or unwind-protect + free-alien)
Another method is to create a static vector. See https://github.com/sionescu/static-vectors for example. (But it is meant for use with CFFI as well.)
A plus is that these (when supported) are not moved by GC, so they can be stored and used by foreign code outside of the call. A minus is that you would need to free it on the lisp side.