Re: Callbacks and FFI Techniques



Aaron W. Hsu wrote:
I am working on some applications that are designed in two different
languages. Part of it in C and the other part in Scheme. There are a
set of Callbacks which the C side will use which need to be mapped to
Scheme functions. These functions are provided by the Scheme system as
pointers to these functions. I would like to have an intialization
function that I can use to set all these callbacks to the right values
at the start of the program. However, what is the appropriate way to
declare these procedures? I was hoping that I could just assign all the
callback values into an array of type void * and then just have the
right function prototypes used in the declaration of the callbacks.

Is it better to use the void * or actually do everything explicitly,
especially considering that there could be a lot of callbacks?

From the C side, you cannot reliably use a void* (or any
other pointer-to-data) to point at a function. Pointers to
functions can only be stored in pointer-to-function variables.

... which raises a problem. There are as many different
kinds of pointers-to-function as there are different kinds of
functions. A pointer-to-function-returning-int is one kind,
and a pointer-to-function-returning-pointer-to-char is another.
So you either have to declare your pointer variable as a type
that matches the function it points to:

int func1(double, char*);
int (*fptr1)(double, char*) = func1;

.... or else you must use a cast to convert the type:

int func2(double, char*);
void (*fptr2)(void) = ((void)(*)(void))func2;

Both of these can be de-mystified somewhat with a typedef:

int func1(double, char*);
typedef int (*IntOfDblAndString)(double, char*);
IntOfDblAndString fptr1 = func1;

int func2(double, char*);
typedef void (*VoidOfVoid)(void);
VoidOfVoid fptr2 = (VoidOfVoid)func2;

So much for the declarations and initializations (or
assignments). But now you've got another problem: At the
point where you use the pointer to call the function, the
type of the pointer must match the actual type of the called
function. Continuing the examples above,

int result1 = fptr1(3.14, "pi");

.... would be correct, but

int result2 = fptr2(3.14, "pi");

.... would be wrong: The type of fptr2 does not match the type
of func2, the function it points to. If there's a mismatch of
this kind (which there isn't in the fptr1 case), you must correct
it with another cast

int result2 = (int (*)(double, char*))fptr2)(3.14, "pi");

.... whose readability, again, can be improved with a typedef:

int result2 = ((IntOfDblAndString)fptr2)(3.14, "pi");

I'll leave the Scheme side of things for someone else to
explain; I'm a Common Lisp guy, not a Schemer.

--
Eric Sosman
esosman@xxxxxxxxxxxxxxxxxxxx
.



Relevant Pages

  • Re: Maps, filters and accumulators
    ... SCHEME programmers would be able to pass procedures as arguments quite ... by passing a pointer to a struct containing anything that needs to last ... typedef int my_data_type; ...
    (comp.lang.c)
  • Re: How to implement callback?
    ... imagine that there's an event that indicates that all process callbacks ... and pass the pointer to a callback function. ... certerial hook manager. ...
    (microsoft.public.windowsce.platbuilder)
  • Re: How to implement callback?
    ... imagine that there's an event that indicates that all process callbacks ... and pass the pointer to a callback function. ... certerial hook manager. ...
    (microsoft.public.windowsce.platbuilder)
  • Re: How to update an agrument passed by name in scheme
    ... > Scheme arguments are passed by value, and there are no pointers as such; ... ;;; Poor-man's structure to hold the `pointer' object. ... (define (%make-pointer a b) ... ((make-pointer var) ...
    (comp.lang.scheme)
  • Re: How to update an agrument passed by name in scheme
    ... >> Scheme arguments are passed by value, and there are no pointers as such; ... >;;; Poor-man's structure to hold the `pointer' object. ... > (define (%make-pointer a b) ... opposed to whatever other language". ...
    (comp.lang.scheme)