[Openmcl-devel] Idiom for creating arrays of C structs
Gary Byers
gb at clozure.com
Tue Jun 2 23:56:20 PDT 2009
In C, a "vector of structs" is very different from "a vector of pointers
to structs"; I'm pretty sure (from the parts of the code that I can see)
that what we're dealing with here is "an array of cpv structs" rather
than "an array of pointers to cpv structs."
If P is a pointer to an array of cpv structs, then in order to access
the I'th element of P by adding (* I <size of cpv struct>) to the address
of P; the resulting pointer would be a pointer to the I'th struct. In
CCL's FFI, that'd be:
(%INC-PTR ptr-returned-from-make-cpv-array (* index size-of-cpv-struct))
And to access the value of the X component of the INDEX'th CPV struct,
(pref (%INC-PTR ptr-returned-from-make-cpv-array (* index size-of-cpv-struct))
#>cpVect.x) ; or whatever.
There's an internal, undocumented function named CCL::%COMPOSITE-POINTER-REF;
it exists solely to allow SETF to work with some macros and allows things
like "setting the I'th element of an array of structures to the value of
another structure", which is pretty obscure. If you see calls to
CCL::%COMPOSITE-POINTER-REF in some macroexpansions, they'd probably be
best read as if they were %INC-PTR calls.
There's a little bit of syntactic sugar (another thing that may be referenced
in the old release notes in the doc directory but may not have made it into
the manual) that can make this a little easier:
(CCL:PAREF array-pointer array-foreign-type index)
Hopefully, the other arguments are self-explanatory; somewhat strangely, PAREF
expects the ARRAY-FOREIGN-TYPE argument to be the type of the array (a pointer
to something), rather than the type of its elements.
Given:
? (def-foreign-type nil
(:struct example
(x :double-float)
(y :double-float)))
NIL
? (ccl:macroexpand-all '(pref (paref p (:* (:struct :example)) 17) :example.x))
(%GET-DOUBLE-FLOAT (%COMPOSITE-POINTER-REF 16 P (/ (THE FIXNUM (* 128 (THE FIXNUM 17))) 8)) (/ 0 8))
which looks a lot scarier than it is.
On Tue, 2 Jun 2009, John Miller wrote:
> Are there any conventions/best practices to follow when working with arrays
> of C structs that are passed back and forth from foreign code? Sorry if this
> has already been discussed in the past, but nothing jumped out at me while
> browsing through the group's archives.
>
> The code in the attached file seems to work on first appearance, creating an
> array of cpVect structures on a call to make-cpv-array. I can do something
> like
> (%get-ptr ptr-returned-from-make-cpv-array (* index
> size-of-cpv-struct))
> and get a cpVect structure back. When I pass the MACPTR returned by
> make-cpv-array to foreign code, however, the block of memory apparently turns
> to mush. A copy of the C code I am calling with my make-cpv-array MACPTR is
> also in the attached file along with some interactions with the Listener.
>
> I guess that #<A Foreign Pointer (:* (:STRUCT :CP<V>ECT)) #x1EF61470> is not
> the same as a cpVect* verts, but I am at a loss to explain why and how to get
> the two to agree.
>
More information about the Openmcl-devel
mailing list