Passing structs by value with cffi-libffi?

强颜欢笑 提交于 2019-12-05 19:34:39

To "load the cffi-libffi system", you need to specify it as dependency in the library's .asd file. (Note: cffi-libffi needs the C library libffi to be installed on your system.)

To be able to use (:struct structure-name), you need to first define the structure with cffi:defcstruct, like this (I will assume here that cffi:defcstruct, cffi:defcfun, and cffi:with-foreign-slots are imported in the current package):

(defcstruct cv-size
  (width :int)
  (height :int))

You can then use (:struct cv-size) in the defcfun like this:

(defcfun ("cvGetSize" %get-size) (:struct cv-size)
  (arr cv-array))

EDIT: Fixed get-size for passed-by-value structs.

And finally define get-size like this:

(defun get-size (arr)
  "Get the dimensions of the OpenCV array ARR. Return a size struct with the
dimensions."
  (let ((%size (%get-size arr)))
    (make-size :width (getf %size 'width)
               :height (getf %size 'height))))

EDIT 2:

If I understand Liam's answer correctly, this is how to write a translate-from-foreign method so that it creates the struct directly, without creating the intermediate plist:

(defmethod cffi:translate-from-foreign (p (type cv-size-type))
  (with-foreign-slots ((width height) p (:struct cv-size))
    (make-size :width width :height height)))

You don't have to define both %get-size and get-size. Instead, you could define

(defcstruct (cv-size :class cv-size-type)
  (width :int)
  (height :int))

(defmethod cffi:translate-from-foreign (p (type cv-size-type))
  (let ((plist (call-next-method)))
    (make-size :width (getf plist 'width)
               :height (getf plist 'height))))

and then define the function get-size directly with the defcfun.

The benefit of doing it this way is anytime you have a function that returns a cv-size, it will automatically get translated. And, if you have foreign functions to which you want to pass a cv-size, define the appropriate method for cffi:translate-into-foreign-memory. You will also get the translation automatically if you use mem-aref on a pointer to the structure. Or, if you call cffi:convert-from-foreign.

In this example, I have used the default plist translation method; you can if you wish directly access the slots without calling (call-next-method).

(BTW, the reason you were under the impression that CFFI could not pass structures by value was that it couldn't until recently; cffi-libffi was introduced with release 0.11.0.)

muyinliu

You just have to add :class xxx to cffi:defcstruct then (cffi:defmethod translate-into-foreign-memory (object (type xxx) pointer) yyyy), it will pass structure by value to a foreign function automatically!! Amazing!!

And (cffi:defmethod translate-from-foreign (pointer (type xxx)) zzzz) will convert the returned structure data into lisp data.

More information please check this answer also by me^_^

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!