Path: utzoo!utgpu!news-server.csri.toronto.edu!cs.utexas.edu!wuarchive!usc!rpi!batcomputer!cornell!cs.cornell.edu!rapo From: rapo@cs.cornell.edu (Andy Rapo) Newsgroups: comp.lang.lisp.franz Subject: Re: Calling LISP functions from C. Message-ID: <1991May10.153446.7573@cs.cornell.edu> Date: 10 May 91 15:34:46 GMT References: Sender: news@cs.cornell.edu (USENET news user) Distribution: comp.lang.lisp.franz Organization: Cornell University, CS Dept., Ithaca, NY Lines: 111 Nntp-Posting-Host: spinet.cs.cornell.edu Emily, I've been doing a lot of C/Lisp interfacing lately with allegro. In order to call a lisp function from C, you need to load the C code into your lisp image. Then you need to make your lisp functions c-callable and register them with Lisp. Lisp stores a pointer to the function in a table that C can access. If the registered Lisp function moves, the pointer in the table is updated. In this way, C can always find the Lisp function. (defun-c-callable scale_z-callback (val) (format t "This is Lisp called with value ~A. ~%" val)) (multiple-value-setq (*ptr1* *index1* *prev-ptr1*) (register-function 'scale_z-callback)) *ptr1* is a pointer to the Lisp function. *index1* is an index into the table of pointers. I haven't used *prev-ptr1* yet. *ptr1* is the value you need for now. You have to pass C the address of the Lisp function that you want to call. The way I have done this is to set up a structure in C that holds poiters to functions. In C the struct looks like this: /* these are all pointer to functions that return int */ typedef struct ptr_type { int (*scale_z)(); int (*scale_y)(); int (*scale_x)(); . . . } ptr_type; ptr_type ptr; This C code would be in a file like c-interface.c. This file would be compiled and the resulting object file, c-interface.o, would be loaded into Lisp. More on this in a sec. In order to assign values to members of the struct I make the struct accessible to Lisp using the defcstruct function. This function makes accessor functions for a c-struct. ;;; MAKE-PTR-STRUCT-ACCESSORS makes accessor functions which, when ;;; supplied with a pointer to a C struct, will return the value ;;; stored there. Setf can be used to modify the C struct. The C ;;; struct exists in C space and is not moved by Lisp garbage collection. (defun make-ptr-struct-accessors () (defcstruct (ptr :malloc) (scale_z :unsigned-long) (scale_y :unsigned-long) (scale_x :unsigned-long) . . . )) Then I can get the value of a c-struct member (i.e. scale_z) by typing (ptr-scale_x *pointer-to-cstruct*). These are like CLOS accessors. I have to supply a pointer to the (ptr-scale_z ...) function so that Lisp can find the c-struct. In C, I've defined the following function which returns the address of the c-struct. ptr_type *get_ptr_address() { return &ptr; } I make this function (and the other C objects I need) available to Lisp by loading the .o file that it is defined in. (load "" :foreign-files '("c-interface.o") :system-libraries '("m" "gl_s")) Next I make Lisp aware of the newly loaded c function. (defforeign 'get_ptr_address :arguments nil :return-type :integer)) And then I call the c function, get_ptr_address, to get the address of the c-struct, *ptr*, and use it with the Lisp accessor functions to get at the values of the c-struct. ;;; SET-PTR-STRUCT-ADDRESS sets *ptr* to be the address of the C ;;; struct which contains pointers to Lisp functions. ;;; These pointers are used by C to "callback" to Lisp. (defun set-ptr-struct-address () (setf *ptr* (get_ptr_address))) (defun set-callback-ptrs () (setf (ptr-scale_z *ptr*) *ptr1*)) Now, the c-struct member, ptr.scale_z, contains *ptr1* which is the address of the Lisp function, scale_z-callback. C can call this Lisp function like this: (*ptr.scale_z)(val); Whew.... Well, its actually very easy to do, and worth the effort. Interfacing between C and Lisp can make life very easy for you later on. If you have any questions let me know. As I said, I've been doing this a lot lately and would be glad to share what I've learned. Andrew Rapo Cornell University Simulation/Robotics