Allocates memory for a list of foreign objects, executes a list of forms which may use the objects across the scope of the macro, and then deallocates the foreign objects.
with-dynamic-foreign-objects bindings &body body => last
binding ::= ( var foreign-type &key initial-element initial-contents fill nelems size-slot )
A symbol to be bound to a foreign type.
A foreign type descriptor to be bound to the variable var .
A form to be executed with bindings in effect.
The macro
with-dynamic-foreign-objects
binds variables according to the list
bindings
, and then executes
body
. Each element of
bindings
is a list which binds a symbol to a pointer which points to a locally allocated instance of a foreign type.
initial-element , initial-contents , fill , nelems and size-slot initialize the allocated instance as if by allocate-foreign-object.
The lifetime of the bound foreign objects, and hence the allocation of the memory they take up, is within the scope of the
with-dynamic-foreign-objects
function.
Any object created with allocate-dynamic-foreign-object within
body
will automatically be deallocated once the scope of the
with-dynamic-foreign-objects
function has been left.
There is an alternative syntax for binding with an optional initial-element which is the only way to supply an initial element in LispWorks 5.0 and previous versions. Like this:
binding ::= ( var foreign-type &optional initial-element )
This alternative syntax is deprecated in favor of the keyword syntax for binding defined in Signatureabove which is supported in LispWorks 5.1 and later.
This example shows the use of
with-dynamic-foreign-objects
with an implicitly created pointer.
typedef struct {
int one;
float two;
} foo ;
__declspec(dllexport) void __cdecl init_alloc(foo *ptr, int a, float b)
{
ptr->one = a;
ptr->two = b;
};
typedef struct {
int one;
float two;
} foo ;
void init_alloc(foo * ptr, int a, float b)
{
ptr->one = a;
ptr->two = b;
};
Here are the FLI definitions interfacing to the above C code:
(fli:define-c-typedef (foo (:foreign-name "foo"))
(:struct (one :int) (two :float)))
(fli:define-foreign-function (init-alloc "init_alloc")
((ptr (:pointer foo))
(a :int)
(b :float))
:result-type :void
:calling-convention :cdecl)
Try this test function which uses
with-dynamic-foreign-objects
to create a transient
foo
object and pointer:
(defun test-alloc (int-value float-value &optional (level 0))
(fli:with-dynamic-foreign-objects ((object foo))
(init-alloc object int-value float-value)
(format t "~%Level - ~D~& object : ~S~& slot one : ~S~& slot two : ~S~&"
level object
(fli:foreign-slot-value object 'one)
(fli:foreign-slot-value object 'two))
(when (> int-value 0)
(test-alloc (1- int-value)
(1- float-value) (1+ level)))
(when (> float-value 0)
(test-alloc (1- int-value)
(1- float-value) (1+ level)))))
(test-alloc 1 2.0)
=>
Level - 0
object : #<Pointer to type FOO = #x007E6338>
slot one : 1
slot two : 2.0
Level - 1
object : #<Pointer to type FOO = #x007E6340>
slot one : 0
slot two : 1.0
Level - 2
object : #<Pointer to type FOO = #x007E6348>
slot one : -1
slot two : 0.0
Level - 1
object : #<Pointer to type FOO = #x007E6340>
slot one : 0
slot two : 1.0
Level - 2
object : #<Pointer to type FOO = #x007E6348>
slot one : -1
slot two : 0.0
A further example using
with-dynamic-foreign-objects
and a pointer created explicitly by allocate-dynamic-foreign-object is given in An example of dynamic memory allocation.