[gambit-list] Re: How to define c-lambda for this routine.

Marc Feeley feeley at iro.umontreal.ca
Fri May 12 17:52:35 EDT 2006


On 12-May-06, at 4:39 PM, Bradley Lucier wrote:

> Marc:
>
> What do I put in my scm code to interface with this routine:
>
> ;;   void rdft(long, long, double *, long *, double *);
>
> And what type of scheme vectors can I pass to this?

You could use (untested):

(c-define-type double* (pointer double))
(c-define-type long* (pointer long))

(define rdft (c-lambda (long long double* long* double*) void "rdft"))

However, there is no automatic conversion from Scheme objects to  
double* and long*, so the above would have to be used with arrays  
allocated from C.  For example you could:

(c-declare "#include <stdlib.h>")

(define make-double-vector
   (c-lambda (int)
             double*
    "___result = malloc(___arg1 * sizeof(double));"))

(define make-long-vector
   (c-lambda (int)
             long*
    "___result = malloc(___arg1 * sizeof(long));"))

(define v1 (make-double-vector 100))
(define v2 (make-long-vector 100))
(define v3 (make-double-vector 100))

(rdft 111 222 v1 v2 v3)

Of course adding accessors and mutators for the C vectors might be  
useful.

You might ask: Why isn't there an automatic conversion from Scheme  
vectors to C vectors?  It is conceivable to add this to Gambit but  
for safety reasons it would have to copy the Scheme vector into a  
newly allocated C vector to be passed to C.  This is required to  
avoid garbage collection problems (i.e. if the garbage collector  
kicks in during the call to C, then in general, the GC might move any  
Scheme vector so it is not safe to simply point to the body of the  
Scheme vector).  Note: this is not true if you use ___STILL objects,  
but it is not easy way to allocate a ___STILL vector from Scheme (one  
way is with (##still-copy (make-f64vector 100)) but this is  
inefficient because it involves copying the vector).

If you know the GC will never be called in the C function or you  
don't care about safety, you could use the following approach.  There  
is a macro ___BODY(obj) defined in include/gambit.h which returns a  
pointer to the body of any memory allocated object.  In the case of  
vectors, it is a pointer to the first element.  So you could write:

(define rdft
   (c-lambda (long long scheme-object scheme-object scheme-object)
             void
    "rdft(___arg1,
          ___arg2,
          (double*)___BODY(___arg3),
          (long*)___BODY(___arg4),
          (double*)___BODY(___arg5));"))

(rdft 111
       222
       (f64vector 1.0 2.0 3.0)
       (u32vector 111 222 333) ; use u64vector if "long" is a 64 bit  
int on your platform
       (f64vector 1.0 2.0 3.0))

There are three things you must remember about this approach: it is  
unsafe, it is unsafe, and it is unsafe.  YMMV.

Marc



More information about the Gambit-list mailing list