Lisp HUG Maillist Archive

Reference-return

Reference-return Hi,

I have to define a foreign function for a C function where an argument can return by reference different kind of types.
This argument is declared in the header of the C source code as: *void outData,  .

When looking for a string, declaration of arg in fli:define-foreign-function (outData (:reference-return (:ef-mb-string :limit 31 :null-terminated-p t))) works well. When looking for a integer (outData (:reference-return :int)) works fine.

When looking for anything –witch is the goal in fact- (outData (:reference-return (:pointer :void))) works also, but the problem is after : I don’t know how to coerce this pointer to the right type and dereference it correctly...

Which operation is automatically done by the :reference-return argument when choosing for instance (:ef-mb-string :limit 31 :null-terminated-p t) as type ? Is it possible to do this operation after I get the pointer ? I didn’t see this very clearly in the manual...

Thanks

Denis


-------------------------------------------------------
Denis Pousseur
70 rue de Wansijn
1180 Bruxelles, Belgique

Tel : 32 (0)2 219 31 09
Mail :  denis.pousseur@compositeurs.be
Website : http://compositeurs.be/pousseur
-------------------------------------------------------

Re: Reference-return

On Friday 20 October 2006 10:46 am, Denis Pousseur wrote:
> This argument is declared in the header of the C source code as: *void
> outData,  .

If I understood your question correctly, I think that you want to declare the 
return type as 

(outData (:reference-return (:pointer :void)))

just like the C header, and then use fli:dereference using the :type keyword 
(to "coerce" the pointer to a different type).

Then, your program logic must determine which type is being returned and 
coerce the void* appropriately (maybe in a "case" statement).

Here is a small sample:

;; create a foreign object, like the one which
;; might be returned from a C function
(setq intp (fli:allocate-foreign-object :type :int))
(setf (fli:dereference intp) 12)
;; check that it dereferences correctly
(fli:dereference intp)

;; create a void*
(setq voidp (fli:allocate-foreign-object :type '(:pointer :void)))

;; put the address of the above int into the void*, which is 
;; how C will return it (an int*, put inside a void*)
(setf (fli:pointer-address voidp) (fli:pointer-address intp))

;; coerce the void* to an int and dereference it
;; the answer should be 12
(fli:dereference voidp :type :int)

The above, translated into C looks kind of like this:

int* intp;
*intp = 12;
printf ("%d\n", *intp);
void* voidp;
voidp = intp;
printf ("%d\n", *(int*)voidp);

If it's still not clear, feel free to ask me for more help.
pt


Re: Reference-return

Well, thanks. It seems logical, but in fact it doesn't work for me.

If I declare the foreign-function with the argument (outData
(:reference-return Uint32)) the result is perfectly normal...
But if I do the same with (outData (:reference-return (:pointer :void)))
get the pointer and than do : (dereference thisPointer :type :int)
LW crashes, with a error message of type :
"signal A [code 0] at 20671181 {inside #<Function ((TOP-LEVEL-FORM 22) . 1)
20671172>}
Eax 0;ebx 0;ecx 200;edx 16C esp21385830;esb2138587C;esi EB;edi EB"

In this case (it seems to be the problem even if I don't understand exactly)
the void pointer returned by the function has the address of the number I
need... (if this number is zero the pointer is a null pointer...).
So, with fli:pointer-adress I can get it (but this works only for unsigned
integer, naturally)

Denis


Le 20/10/06 17:51, « [NOM] » <[ADRESSE]> a écrit :

> On Friday 20 October 2006 10:46 am, Denis Pousseur wrote:
>> This argument is declared in the header of the C source code as: *void
>> outData,  .
> 
> If I understood your question correctly, I think that you want to declare the
> return type as 
> 
> (outData (:reference-return (:pointer :void)))
> 
> just like the C header, and then use fli:dereference using the :type keyword
> (to "coerce" the pointer to a different type).
> 
> Then, your program logic must determine which type is being returned and
> coerce the void* appropriately (maybe in a "case" statement).
> 
> Here is a small sample:
> 
> ;; create a foreign object, like the one which
> ;; might be returned from a C function
> (setq intp (fli:allocate-foreign-object :type :int))
> (setf (fli:dereference intp) 12)
> ;; check that it dereferences correctly
> (fli:dereference intp)
> 
> ;; create a void*
> (setq voidp (fli:allocate-foreign-object :type '(:pointer :void)))
> 
> ;; put the address of the above int into the void*, which is
> ;; how C will return it (an int*, put inside a void*)
> (setf (fli:pointer-address voidp) (fli:pointer-address intp))
> 
> ;; coerce the void* to an int and dereference it
> ;; the answer should be 12
> (fli:dereference voidp :type :int)
> 
> The above, translated into C looks kind of like this:
> 
> int* intp;
> *intp = 12;
> printf ("%d\n", *intp);
> void* voidp;
> voidp = intp;
> printf ("%d\n", *(int*)voidp);
> 
> If it's still not clear, feel free to ask me for more help.
> pt
> 



-------------------------------------------------------
Denis Pousseur
70 rue de Wansijn
1180 Bruxelles, Belgique

Tel : 32 (0)2 219 31 09
Mail :  denis.pousseur@compositeurs.be
Website : http://compositeurs.be/pousseur
-------------------------------------------------------





Re: Reference-return

On Friday 20 October 2006 01:34 pm, Denis Pousseur wrote:
> Well, thanks. It seems logical, but in fact it doesn't work for me.
>
> If I declare the foreign-function with the argument (outData
> (:reference-return Uint32)) the result is perfectly normal...
> But if I do the same with (outData (:reference-return (:pointer :void)))
> get the pointer and than do : (dereference thisPointer :type :int)
> LW crashes, with a error message of type :

I looked at it a bit more carefully.

Your problem is that :reference-return automatically converts from C to lisp 
on the way back, but, LW cannot know which type to convert it to (since there 
is more than one possible type).

According to my understanding of your problem, the following piece of code 
seems to do what you want.  The calling function - your lisp program - must 
allocate memory which the C function pokes results into.  You allocate the 
memory as "foreign" and then convert it back to lisp when you want to use the 
results in lisp.

For your problem, the interesting function is "lisp-calls-c".  All of the 
other cruft is just a test harness that creates the effect of two c-like 
foreign functions (in lisp) that perform the c-like operations on the 
pointers.



;;; a faked C function that takes a pointer
;;; as a arg and pokes an int into it
(fli:define-foreign-function pokeint ((p (:pointer :void)))
  :result-type :void)

(fli:define-foreign-callable
    ("pokeint" :result-type :void)
    ((p (:pointer :int)))
  (setf (fli:dereference p :type :int) 42))

;;; a faked C function that takes a pointer
;;; as a arg and treats it like a C string (an array of bytes)
(fli:define-foreign-function pokestring ((p (:pointer :void)))
  :result-type :void)

(fli:define-foreign-callable
    ("pokestring" :result-type :void)
    ((ptr (:pointer :void)))
  (fli:with-coerced-pointer (p :type '(:unsigned :byte)) ptr
    (setf (fli:dereference p) #\H)
    (fli:incf-pointer p)
    (setf (fli:dereference p) #\i)
    (fli:incf-pointer p)
    (setf (fli:dereference p) #\Null)
    (fli:incf-pointer p)))
  
;;; a lisp function that creates a C int and a C string
;;; then passes these, as void* pointers, to C functions which
;;; poke results into variables
(defun lisp-calls-c ()
  (let ((intp (fli:allocate-foreign-object :type :int))
        (strp (fli:allocate-foreign-object :type '(:unsigned :byte) :nelems 32
                                        :initial-contents '(49 50 51 52 0))))
    ;;
    (setf (fli:dereference intp) 12)
    (format t "The original int is ~A~%" (fli:dereference intp))
    (format t "The original string is /~A/~%" 
                 (fli:convert-from-foreign-string strp))
    ;; now call the C functions and print the new results
    (pokeint intp)
    (format t "The int is ~A~%" (fli:dereference intp))
    (pokestring strp)
    (format t "The string is /~A/~%" (fli:convert-from-foreign-string strp))))

pt


Re: Reference-return

That's it!

Thanks a lot Paul !

Denis

-------------------------------------------------------
Denis Pousseur
70 rue de Wansijn
1180 Bruxelles, Belgique

Tel : 32 (0)2 219 31 09
Mail :  denis.pousseur@compositeurs.be
Website : http://compositeurs.be/pousseur
-------------------------------------------------------

Le 20/10/06 22:18, « [NOM] » <[ADRESSE]> a écrit :

> On Friday 20 October 2006 01:34 pm, Denis Pousseur wrote:
>> Well, thanks. It seems logical, but in fact it doesn't work for me.
>> 
>> If I declare the foreign-function with the argument (outData
>> (:reference-return Uint32)) the result is perfectly normal...
>> But if I do the same with (outData (:reference-return (:pointer :void)))
>> get the pointer and than do : (dereference thisPointer :type :int)
>> LW crashes, with a error message of type :
> 
> I looked at it a bit more carefully.
> 
> Your problem is that :reference-return automatically converts from C to lisp
> on the way back, but, LW cannot know which type to convert it to (since there
> is more than one possible type).
> 
> According to my understanding of your problem, the following piece of code
> seems to do what you want.  The calling function - your lisp program - must
> allocate memory which the C function pokes results into.  You allocate the
> memory as "foreign" and then convert it back to lisp when you want to use the
> results in lisp.
> 
> For your problem, the interesting function is "lisp-calls-c".  All of the
> other cruft is just a test harness that creates the effect of two c-like
> foreign functions (in lisp) that perform the c-like operations on the
> pointers.
> 
> 
> 
> ;;; a faked C function that takes a pointer
> ;;; as a arg and pokes an int into it
> (fli:define-foreign-function pokeint ((p (:pointer :void)))
>   :result-type :void)
> 
> (fli:define-foreign-callable
>     ("pokeint" :result-type :void)
>     ((p (:pointer :int)))
>   (setf (fli:dereference p :type :int) 42))
> 
> ;;; a faked C function that takes a pointer
> ;;; as a arg and treats it like a C string (an array of bytes)
> (fli:define-foreign-function pokestring ((p (:pointer :void)))
>   :result-type :void)
> 
> (fli:define-foreign-callable
>     ("pokestring" :result-type :void)
>     ((ptr (:pointer :void)))
>   (fli:with-coerced-pointer (p :type '(:unsigned :byte)) ptr
>     (setf (fli:dereference p) #\H)
>     (fli:incf-pointer p)
>     (setf (fli:dereference p) #\i)
>     (fli:incf-pointer p)
>     (setf (fli:dereference p) #\Null)
>     (fli:incf-pointer p)))
>   
> ;;; a lisp function that creates a C int and a C string
> ;;; then passes these, as void* pointers, to C functions which
> ;;; poke results into variables
> (defun lisp-calls-c ()
>   (let ((intp (fli:allocate-foreign-object :type :int))
>         (strp (fli:allocate-foreign-object :type '(:unsigned :byte) :nelems 32
>                                         :initial-contents '(49 50 51 52 0))))
>     ;;
>     (setf (fli:dereference intp) 12)
>     (format t "The original int is ~A~%" (fli:dereference intp))
>     (format t "The original string is /~A/~%"
>                  (fli:convert-from-foreign-string strp))
>     ;; now call the C functions and print the new results
>     (pokeint intp)
>     (format t "The int is ~A~%" (fli:dereference intp))
>     (pokestring strp)
>     (format t "The string is /~A/~%" (fli:convert-from-foreign-string strp))))
> 
> pt
> 









Updated at: 2020-12-10 08:47 UTC