From: Jerome A. <Jer...@fr...> - 2004-08-25 15:05:52
|
Hi, there ! I'm trying to use an external C function which returns a pointer to a structure. I have two needs: 1. I need to pass the pointer to other functions. 2. I need to inspect some of the fields of the structure. Here are the solutions I was able to implement. 1. Using c-pointer. I can use the given c-pointer as an anonymous handle, and pass it to other functions. It works fine, but I can't find a way to access the structure. Well, it seems fair to me: only ugly hacks should allow me to manipulate data behind a c-pointer. 2. Using (c-ptr mystruct). This way, I can dig into the structure. But it looks like the c-ptr type description is only used to describe the C function, and is bypassed in the resulting lisp data: the lisp function returns directly a structure, instead of a pointer I would have to ffi::deref. Therefore, the pointer value is lost, and I can't call the other functions. Is my analysis of the (c-ptr struct) behavior correct ? Is there a way to force FFI to return a c-ptr, which I could either use as-is, or deref when I want to access the struct ? Thanks for any help, Jerome. |
From: Hoehle, Joerg-C. <Joe...@t-...> - 2004-08-25 16:47:11
|
Jerome Abela asked: >Is there a way to force FFI to return a c-ptr, which I could either use >as-is, or deref when I want to access the struct ? As you noticed, C-PTR leads to immediate transformation of a foreign thing to Lisp data. This is not TRT for the many cases where one wants to deal with references and (possibly partially) dereference the foreign data later. You have to use c-pointer as :return-type. Then you have to construct a FOREIGN-VARIABLE object out of the FOREIGN-ADDRESS object that you got. I just recently sketched again in this list how this can be done. It usually goes as follows: (defun dereference-now (the-address) (with-c-var (x '(c-ptr my-data-type)) (setf (cast x 'c-pointer) the-address) (list (deref x) (slot (deref x) 'foo) x)) I had thought of introducing a new declaration like this (c-pointer <c-type>) ; neither c-pointer nor (c-ptr <c-type)! As a return-type, i.e. when converting to Lisp, it would produce a typed FOREIGN-VARIABLE pointer object. It's exactly what could be needed here. However, introducing this conversion is not enough. E.g. consider a (c-struct foo (c-pointer mystruct)), i.e. a reference in a structure. You could read that slot but how yould your write to it? So soon people will also want the Lisp-side->C conversion. This one is not well defined at all. At least, I don't want to invent an implementation of c-subtype-p, which one may think is needed for type safety. What I mean is, suppose you have (c-pointer (c-array character 30)). Would it be acceptable to supply a a) #<foreign-variable (c-array-max character 64)> b) #<foreign-variable (c-array-max uin8 30)> c) #<foreign-address> d) #<foreign-variable c-string> e) some Lisp string f) some Lisp array g) #<foreign-variable (c-ptr (c-ptr bar))> h) #<foreign-variable character> One of my concerns is that if this conversion were implemented, *I* would object both type-checking and CAST'ing (to comply with strict type-checking) because of the performance penalty they cause, which would make CLISP's FFI even slower than it is today, compared to all the other native code compilers where CAST'ing is mostly a no-op and checking of foreign types is uniquely a compile-time issue. I.e. CLISP would then do less checks on foreign pointers than any C compiler. Is that acceptable? Summary: o foreign world -> #<FOREIGN-VARIABLE> is very useful/handy o it should not come alone, because irregularities make jobs harder (e.g. making UFFI work) o the only acceptable choice for the converse conversion of the new (c-pointer <c-type>) would be to accept any foreign entity that embeds a pointer (i.e. foreign-address -variable and -function. But that does not look clean at all. So what's next? A compromise might be to restrict this to :return-type of functions. But why not also in structures (esp. since from an implementation POV, it's the same, not separate code in src/foreign.d). That's also not proper, because parse-c-type cannot generally know whether it's parsing something for :return-type or not (consider (c-ptr (c-ptr (c-pointer mystruct))) or def-c-type declarations). Regards, Jorg Hohle. |
From: Jerome A. <Jer...@fr...> - 2004-08-25 17:40:22
|
On Wed, Aug 25, 2004 at 06:45:24PM +0200, Hoehle, Joerg-Cyril wrote: > Jerome Abela asked: > >Is there a way to force FFI to return a c-ptr, which I could either use > >as-is, or deref when I want to access the struct ? > > [very documented answer] Awesome ! Thanks a lot for this very deep answer, covering both my immediate needs and the next few questions I could have on that matter :-) I have to confess I didn't understood everything (like why the type checking is so slow while navigating among foreign types - slower than converting it into lisp types ?). But I keep it, and I'll try to read it again as my level at lisp will improve :-) Thanks again, Jerome. |