[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [spr1064] adjustable array from Lisp to C??

   Date: Tue, 13 Feb 90 09:41:15 PST
   From: klin@argon.berkeley.edu (Kuang-Kuo Lin)

   I am trying to pass a string with variable size from Lisp to C,
   and expect that C would change the value of the string.

In C, an array is simply treated as a pointer to the first element of
the array.  In Lisp an array is an object with header information
which may include the size, adjustable flag, fill-pointer information,

When an array is passed to C through the foreign function interface,
only the pointer to the data block is passed.  The other header
information is not readily available to the C program.  Therefore, if
you want to change the fill-pointer or adjust the array, you can't do
that in C without going back into Lisp.

If you really do want to pass a string buffer from Lisp to C and have
C fill it, then you should create a simple-string (using MAKE-STRING)
with a size no smaller than the maximum amount that your C function
will want to write and pass that to C.

If, on the other hand, you are less concerned about having C overwrite
a lisp array, and just have your C function return its own array, you
can use the Allegro function FF:CHAR*-TO-STRING (I believe this
function started being available with Allegro 3.1).  With this
function, you can just have your C function return a C string as an
integer (ie, pointer to the character array).  Then FF:CHAR*-TO-STRING
will create a lisp string from that pointer.  There is an inverse
function FF:STRING-TO-CHAR* that returns the integer to the beginning
of the data block in the Lisp string.

Finally, if you don't have FF:CHAR*-TO-STRING already in your Allegro,
you can use the following definition. It first determines the length
of the string, then allocates a Lisp string, and finally copies the
characters one-by-one.  It is quite efficient in execution.

   (defcstruct (c-string :malloc) (char 1 :char))

   (defun char*-to-string (address)
     "Create a Lisp string copy of a C string"
     (declare (optimize (speed 3))
	      (integer address))
     (if (eq 0 address)
	 (error "0 is not a valid character pointer"))
     (let* ((length
	     (do* ((i 0 (1+ i))
		   (intchar (c-string-char address i)
		    	    (c-string-char address i)))
		  ((eq 0 intchar) i)))
	    (string (make-string length)))
       (declare (simple-string string)
		(fixnum length i))
       (do* ((i 0 (1+ i))
	    ((= i length))
	    (declare (optimize (safety 0))
		     (fixnum i)
		     (string-char char)
		     (simple-string str))
	    (setq char (code-char (c-string-char address i)))
	    (setf (schar string i) char))

If you don't need to create a real Lisp array object and only need to
access the individual characters of the C string in place (the way C
itself does) the C-STRING-CHAR function defined by the DEFCSTRUCT is
all you need.  It is setfable and very fast, since the compiler
opencodes it.

Charles A. Cox, Franz Inc.        1995 University Avenue, Suite 275
Internet: cox@franz.com           Berkeley, CA  94704
uucp:     uunet!franz!cox         Phone: (415) 548-3600    FAX: (415) 548-8253