Subject: FFI

From: Martin Atzmueller <[email-masked]>
Date: Sat, 29 May 1999 03:40:21 +0200

Hi

I want to call a foreign c-function from Clisp by def-call-out.
The function's argument is a 2-dimensional array of double-floats.
So the c-function is defined as "void bar (double * x) ...".
But with the FFI it seems to be the case, that I can't call it without
specifying the precise dimensions of the array.
I tried to define the parameter of the FFI-conversion-function as "c-pointer"
but this didn't help, because Clisp couldn't convert the 2-dim array
appropriately.

Is there a way to solve this, e.g. can I call the function with the FFI using
arrays of different dimensions as arguments?

Thanks
Martin

---

From: Bodo Moeller <[email-masked]>
Date: Sat, 29 May 1999 16:21:55 +0200

> So the c-function is defined as "void bar (double * x) ...".

That's not a two-dimensional array; it's just a pointer to double,
which means (with the implicit type conversion rules of C -- an array
type value is always converted into a pointer to the first element,
except when used with the & or sizeof operator) that it can be used
for *one*-dimensional arrays.

> specifying the precise dimensions of the array.

It's exactly like that in C; e.g.

     void bar (double (*x)[10]);

(x is a pointer to an array with 10 elements of type "double").  You
cannot write

     void bar (double (*x)[]);

---

From: Dobes Vandermeer <[email-masked]>
Date: Sat, 29 May 1999 15:35:47 -0700

>      void bar (double (*x)[]);

What about void bar(double **x), which is functionally equivalent?

Did you actually try that, BTW?  It looks to me like "double *x[]" would
work just fine as well, but thats just a guess.

CU
Dobes

---

From: Bodo Moeller <[email-masked]>
Date: Sun, 30 May 1999 01:43:58 +0200

> What about void bar(double **x), which is functionally equivalent?

It's not.  "double **x" means that x is a pointer to a pointer which
points to a double.  This can mean that x actually points to the first
element of an array (of pointers to double), but in any case *x is a
pointer, not an array.

> work just fine as well, but thats just a guess.

"double *x[]" in the function prototype works just as well as
"double **x", but these are entirely different from "double (*x)[]".
(Note that the [] has higher precedence than *.)

In a variable declaration, double *x[] and double **x would be
different things:

void
some_function(double arg1, double arg2, double arg3)
{
    double *x[] = {&arg1, &arg2, &arg3}; /* x is an array of pointers
                                          * to double. */
    double **y = &(x[0]); /* y is a pointer to a pointer to double. */

    /* ... */
}

Instead of &(x[0]) (which, according to the C precedence rules, could
just as well be written as "&x[0]") it is more customary to write just
x, but one should always keep in mind that pointers and arrays are
*not* equivalent.  E.g., in some_function, sizeof x will be
three times the size of a single pointer to double (3*4, say), while
sizeof y will be the size of a single pointer (e.g. 4).
When you write "y = x;" with declarations as above, you invoke one of
the magic C rules for automatic conversion.

A related rule applies to function prototypes -- in prototypes
(but not in ordinary variable declarations), some_type x[]
or even some_type x[42] is automatically interpreted as some_type *x.
(You cannot assign whole arrays [unless they are wrapped into a
struct or union], so a function parameter of array type can never
exist.)  The idea is that you can make visible in the function
declaration that the function argument is not just the pointer to an
isolated value, but to the first element of an array -- i.e. that
x + 1, x + 2, ... are meaningful pointers to other elements of the
same array (if the array is that large).  But this conversion rule
does not apply to array types "deeper" in the type declaration (it
just wouldn't make sense), so "some_type x[][]" and "some_type *(x[])" 
are *not* the same.

I suggest that you read the explanations on these issues in K&R 
(in the "C reference manual" appendix) if this is not clear to you.

---

From: Martin Atzmueller <[email-masked]>
Date: Mon, 31 May 1999 00:51:48 +0200

> for *one*-dimensional arrays.

I have to confess that I am no C expert.
But the thing hinted at above is exactly what I wanted. I tried to port code
that was written using the ACL-FFI and there the arguments for the foreign
function:  void bla (double * x, double * y, int dim-x, int dim-y), for
example, were defined as  :arguments ((array double-float) (array double-float)
integer integer).

It seems that for the ACL-FFI the number of dimensions does not matter when
passing an array since it is converted to a pointer to the first element, or so
I guess.

My problem is that I want to have a foreign function that accepts arrays of
different dimensions, since I do not know the exact dimensions of the array that
gets passed to the function.
But so far I did not find a solution with the Clisp-FFI.
The imp-notes for Clisp say that one has to write (c-ptr (c-array ({dims}*) )
when passing an array to a c-function, but just writing (c-ptr (c-array () )
does not help in this case.

---

From: Bruno Haible <[email-masked]>
Date: Mon, 31 May 1999 11:17:17 +0200 (MET DST)

> specifying the precise dimensions of the array.

You can do it in two steps:

  1. Passing a linear array of `double', whose length is the product
     of your matrix' dimensions. This can be done using the trick in
     example 5 in impnotes.html (or foreign.txt): You cast the function
     type

        (cast your_function
             `(c-function
                (:arguments (v (c-ptr (c-array double-float ,n))))
                (:return-type (c-ptr (c-array double-float ,n))
                              :malloc-free
              ) )
        )

  2. Use MAKE-ARRAY with :DISPLACED-TO argument to "convert" your
     1-dimensional Lisp array into a 2-dimensional Lisp array.

Bruno