[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.
In
http://cvs.pulsar-zone.net/cgi-bin/cvsweb.cgi/mmondor/mmsoftware/cl/server/const-file.lisp?rev=1.7;content-type=text%2Fplain
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.
--
Matt
More information about the ecl-devel
mailing list