[Ecls-list] Low-level FFI -- dereferencing a C string

Matthew Mondor mm_lists at pulsar-zone.net
Fri Feb 1 18:26:51 UTC 2013

On Fri, 01 Feb 2013 09:34:48 -0700
Alfred Steffens Jr <apsteffe at netwood.net> wrote:

> I have an ECL interpreter embedded in a C application, linked with 
> -lecl.   I have a global string
> char name[32];
> strcpy(name, "hello");
> The C function GetName returns the address of name[],
> int GetName()
> { return (int)name); }

First I recommend to be very careful, as an int might not be able to
hold an address (like on most 64-bit architectures, including amd64,
with an ABI where int is 32-bit and a pointer 64-bit).  You probably
really want something like  const char *.  For the same reason you want
to make sure that you provide a prototype for the function, such that C
really knows at compile time that a pointer is expected (as opposed to
ANSI C's default int return type).

> I use a c-inline to call GetName from Lisp to return the address.
> (defun get-current-address ()
>     (ffi:c-inline () () :int "GetName()" :one-liner t))

Here it's possible for get-current-address to return a :pointer-void
instead of an :int too, (which will internally automatically create a
foreign-pointer object for you).

> This seems to work fine.  But I want to dereference ptr to display the 
> string in Lisp.  What am I missing?  Can you show an example?

If you need to have a CL friendly object or string making use of that
foreign data, you could decode the data into a vector of characters, or
assuming that all characters are ascii, create a vector of base-char
pointing to it, or similar.

there's an example macro for instance which creates a CL
unsigned-byte-8 vector out of the loaded contents of a file (in this
case used for compile-time static data blob embedding purposes).  This
does not technically use UFFI though, but the ECL native inline C FFI
features.  Of course, the ECL vector union supports various types
(vector->vector.self.b8 is being used here to store bytes in this case).

There also is the function ecl_cstring_to_base_string_or_nil() which
can do this for C strings already, but it probably would have trouble
with non-ASCII characters.  If you do have unicode strings, you could
first create a byte vector like in the above example, and using ECL
sequence stream functions decode your byte vector to an actual ECL
unicode characters string.  Also note that ECL FFI supports a :cstring
type, I think that this has the same limitations. 

More information about the ecl-devel mailing list