Передача структур по значению с помощью cffi-libffi?

У меня сложилось впечатление, что CFFI не может передать структуры по значению, но документация CFFI гласит:

Чтобы передать или вернуть структуру по значению функции, загрузите систему cffi-libffi и задайте структуру как (:struct structure-name), Чтобы передать или вернуть указатель, вы можете использовать либо :pointer или же (:pointer (:struct structure-name)),

Я переупаковываю функцию cl-opencv get-size, которая является оберткой для этой функции opencv:

CvSize cvGetSize(const CvArr* arr)

и поскольку я не думаю, что CFFI имел возможность передавать структуры по значению с помощью системы cffi-libffi, когда автор cl-opencv написал библиотеку, ему пришлось использовать весь следующий код для переноса cvGetSize:

 (defmacro make-structure-serializers (struct slot1 slot2)
  "Create a serialization and deserialization function for the
structure STRUCT with integer slots SLOT1 and SLOT2. These functions
will pack and unpack the structure into an INT64."
  (let ((pack-fn (intern (concatenate 'string (string struct) 
                       (string '->int64))))
    (slot1-fn (intern (concatenate 'string (string struct) "-" 
                        (string slot1))))
    (slot2-fn (intern (concatenate 'string (string struct) "-" 
                        (string slot2))))
    (unpack-fn (intern (concatenate 'string (string 'int64->) 
                    (string struct))))
    (make-fn (intern (concatenate 'string (string 'make-) 
                       (string struct)))))
     `(progn
        (defun ,pack-fn (s)
     (+ (,slot1-fn s) (ash (,slot2-fn s) 32)))
        (defun ,unpack-fn (n)
     (,make-fn ,slot1 (logand n #x00000000ffffffff)
            ,slot2 (ash n -32))))))


;; CvSize - Input = (defparameter a (make-size :width 640 :height 480)) Output = #S(SIZE :WIDTH 640 :HEIGHT 480) for 
;; following the two.
(defstruct size (width 0) (height 0))
(make-structure-serializers :size :width :height)

;; CvSize cvGetSize(const CvArr* arr)
(cffi:defcfun ("cvGetSize" %get-size) :int64
  (arr cv-array))

(defun get-size (arr)
  "Get the dimensions of the OpenCV array ARR. Return a size struct with the
dimensions."
  (let ((nsize (%get-size arr)))
     (int64->size nsize)))

Учитывая документацию CFFI, приведенную выше, как бы мне это передать? cvGetSize структура CvSize по значению?

Я намереваюсь обновить пакет cl-opencv, и я хотел бы знать, где и как в пакете cl-opencv я бы "загрузил систему cffi-libffi" согласно документации CFFI, а где "указать структуру как (:struct structure-name)"и" использовать либо: указатель, либо (: указатель (: имя структуры структуры))" " чтобы передать или вернуть указатель."

Я мог бы использовать подробные инструкции о том, как сделать это, используя выше cvGetSize обертка:

;; CvSize cvGetSize(const CvArr* arr)
(cffi:defcfun ("cvGetSize" %get-size) :int64
  (arr cv-array))

(defun get-size (arr)
  "Get the dimensions of the OpenCV array ARR. Return a size struct with the
dimensions."
  (let ((nsize (%get-size arr)))
     (int64->size nsize)))

Редактировать для @Rörd

Я ценю ваш ответ

В любом случае я получаю ту же ошибку... но в целях тестирования, скажем, я загружаю cffi-libffi в мою текущую сессию следующим образом (с выводом)

CL-OPENCV> (asdf:oos 'asdf:load-op :cffi-libffi) 
#<ASDF:LOAD-OP NIL {10076CCF13}>
NIL

он загружается, поэтому я запускаю только defcfun и defcstruct, которые вы указали следующим образом (с выводом):

 CL-OPENCV> (cffi:defcstruct cv-size
           (width :int)
           (height :int))

  (:STRUCT CV-SIZE)
  CL-OPENCV> 
  (defcfun ("cvGetSize" %get-size) (:struct cv-size)
    (arr cv-array))
  ; in: DEFCFUN ("cvGetSize" %GET-SIZE)
  ;     ("cvGetSize" CL-OPENCV::%GET-SIZE)
  ; 
  ; caught ERROR:
  ;   illegal function call
  ; 
  ; compilation unit finished
  ;   caught 1 ERROR condition

  Execution of a form compiled with errors.
  Form:
    ("cvGetSize" %GET-SIZE)
  Compile-time error:
    illegal function call
     [Condition of type SB-INT:COMPILED-PROGRAM-ERROR]

  Restarts:
   0: [RETRY] Retry SLIME REPL evaluation request.
   1: [*ABORT] Return to SLIME's top level.
   2: [ABORT] Abort thread (#<THREAD "repl-thread" RUNNING {1007BA8063}>)

      Backtrace:
             0: ((LAMBDA ()))
                 [No Locals]
             1: (SB-INT:SIMPLE-EVAL-IN-LEXENV ("cvGetSize" %GET-SIZE) #<NULL-LEXENV>)
                 Locals:
                   SB-DEBUG::ARG-0 = ("cvGetSize" %GET-SIZE)
                   SB-DEBUG::ARG-1 = #<NULL-LEXENV>
             2: (SB-INT:SIMPLE-EVAL-IN-LEXENV (DEFCFUN ("cvGetSize" %GET-SIZE) (:STRUCT CV-SIZE) (ARR CV-ARRAY)) #<NULL-LEXENV>)
                 Locals:
                   SB-DEBUG::ARG-0 = (DEFCFUN ("cvGetSize" %GET-SIZE) (:STRUCT CV-SIZE) (ARR CV-ARRAY))
                   SB-DEBUG::ARG-1 = #<NULL-LEXENV>
             3: (EVAL (DEFCFUN ("cvGetSize" %GET-SIZE) (:STRUCT CV-SIZE) (ARR CV-ARRAY)))
                 Locals:

Я знаю, что libffi установлен правильно, потому что с загруженным gsll (который использует cffi-libffi) я запускаю тесты gsll, и они все проходят, как показано здесь (с выводом)

(ql:quickload "lisp-unit")
  (in-package :gsl)
  (lisp-unit:run-tests)
To load "lisp-unit":
  Load 1 ASDF system:
    lisp-unit
     Loading "lisp-unit"
..................................
Unit Test Summary
 | 4023 assertions total
 | 4022 passed
 | 1 failed
 | 0 execution errors
 | 0 missing tests

#<TEST-RESULTS-DB Total(4023) Passed(4022) Failed(1) Errors(0)>

Кажется, он не вызывает defcfun с (:struct cv-size) в качестве проблемы, потому что, когда я называю это как

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

я получаю ту же ошибку

Execution of a form compiled with errors.
Form:
  ("cvGetSize" %GET-SIZE)
Compile-time error:

Я могу запустить мою структуру ipl-изображения, хотя, как это

CL-OPENCV> ;; ;(cffi:foreign-type-size '(:struct ipl-image)) = 144
(cffi:defcstruct ipl-image
(n-size :int)
(id :int)
(n-channels :int)
(alpha-channel :int)
(depth :int)
(color-model :pointer) 
(channel-seq :pointer) 
(data-order :int)
(origin :int)
(align :int)
(width :int)
(height :int)
(roi :pointer)
(mask-roi :pointer)
(image-id :pointer)
(tile-info :pointer)
(image-size :int)
(image-data :string)
(width-step :int)
(border-mode :pointer)
(border-const :pointer)
(image-data-origin :string))

   output>(:STRUCT IPL-IMAGE)

и моя обертка create-image теперь с загруженным cffi-libffi и ваша (:struct ipl-image) на ней работает нормально, хотя... показывается с выводом

;; IplImage* cvCreateImage(CvSize size, int depth, int channels)
(cffi:defcfun ("cvCreateImage" %create-image) (:struct ipl-image)
  (size :int64)
  (depth :int)
  (channels :int))

(defun create-image (size depth channels)
  "Create an image with dimensions given by SIZE, DEPTH bits per
channel, and CHANNELS number of channels."
 (let ((nsize (size->int64 size)))
    (%create-image nsize depth channels)))

СОЗДАТЬ-IMAGE

но когда я бегу

(defparameter img-size (make-size :width 640 :height 480))

(defparameter img (create-image img-size +ipl-depth-8u+ 1))

создать изображение при repl ничего не происходит repl просто зависает...

но когда я запускаю оболочку создания изображения с ipl-изображением вместо (:struct ipl-image)

я могу запустить:

 (defparameter img-size (make-size :width 640 :height 480))

 (defparameter img (create-image img-size +ipl-depth-8u+ 1))

хорошо, затем запустите это для доступа к значениям структуры (с выходом)

 (cffi:with-foreign-slots ((
  n-size
  id
  n-channels
  alpha-channel
  depth
  color-model
  channel-seq
  data-order
  origin
  align
  width
  height
  roi
  mask-roi
  image-id
  tile-info
  image-size
  image-data
  width-step
  border-mode
  border-const
  image-data-origin) img (:struct ipl-image))
            (cffi:mem-ref img :char )
            (format t "n-size ~a ~%" n-size)
            (format t "id ~a ~%" id)
            (format t "n-channels ~a ~%" n-channels)
            (format t "alpha-channel ~a ~%" alpha-channel)
            (format t "depth ~a ~%" depth)
            (format t "color-model ~a ~%" color-model)
            (format t "channel-seq ~a ~%" channel-seq)
            (format t "data-order ~a ~%" data-order)
            (format t "origin ~a ~%" origin)
            (format t "align ~a ~%" align)
            (format t "width ~a ~%" width)
            (format t "height ~a ~%" height)
            (format t "roi ~a ~%" roi)
            (format t "mask-roi ~a ~%" mask-roi)
            (format t "image-id ~a ~%" image-id)
            (format t "tile-info ~a ~%" tile-info)
            (format t "image-size ~a ~%" image-size)
            (format t "image-data ~a ~%" image-data)
            (format t "width-step ~a ~%" width-step)
            (format t "border-mode ~a ~%" border-mode)
            (format t "border-const ~a ~%" border-const)
            (format t "image-data-origin ~a ~%" image-data-origin))
  output>
  n-size 144 
  id 0 
  n-channels 1 
  alpha-channel 0 
  depth 8 
  color-model #.(SB-SYS:INT-SAP #X59415247) 
  channel-seq #.(SB-SYS:INT-SAP #X400000000) 
  data-order 640 
  origin 480 
  align 0 
  width 0 
  height 0 
  roi #.(SB-SYS:INT-SAP #X00000000) 
  mask-roi #.(SB-SYS:INT-SAP #X00000000) 
  image-id #.(SB-SYS:INT-SAP #X0004B000) 
  tile-info #.(SB-SYS:INT-SAP #X7FFFF7F04020) 
  image-size 640 
  image-data NIL 
  width-step 0 
  border-mode #.(SB-SYS:INT-SAP #X00000000) 
  border-const #.(SB-SYS:INT-SAP #X00000000) 
  image-data-origin  

но я не получаю структуру по значению я получаю

 color-model #.(SB-SYS:INT-SAP #X59415247) 

который, когда я cout это значение img->colorModel в с этим

IplImage* img=cvCreateImage(cvSize(640,480), IPL_DEPTH_8U, 3);
cout << "colorModel = " << endl << " " << img->colorModel << endl << endl;

output> colorModel = 
 RGB

поэтому любая помощь будет высоко ценится

хорошо, еще 1 редактировать:

Я попробовал еще раз, и это сработало, вот мой вывод

  CL-OPENCV> (asdf:oos 'asdf:load-op :cffi-libffi)
  #<ASDF:LOAD-OP NIL {1006D7B1F3}>
  NIL
  CL-OPENCV> 
  ;; ;(cffi:foreign-type-size '(:struct cv-size)) = 8
  (cffi:defcstruct cv-size
      (width :int)
      (height :int))

  ;; CvSize cvGetSize(const CvArr* arr)
  (cffi:defcfun ("cvGetSize" %get-size) (:struct cv-size)
    (arr cv-array))

  STYLE-WARNING: redefining CL-OPENCV::%GET-SIZE in DEFUN
  %GET-SIZE
  CL-OPENCV> 

   (defparameter img-size (make-size :width 640 :height 480))

  (defparameter img (create-image img-size +ipl-depth-8u+ 1))

  IMG
  CL-OPENCV> 

   (defparameter size (%get-size img))
  SIZE
  CL-OPENCV> size
  (HEIGHT 480 WIDTH 640)
  CL-OPENCV> 

не знаю, что я сделал неправильно в первый раз, но... если вы можете проверить мои результаты и убедиться, что я только что передал структуру по значению, я был бы всегда благодарен

спасибо Рорд

хорошо, еще одно редактирование, если вы все еще заинтересованы в том, чтобы помочь мне отладить Rord

если получаю ошибку:

  The value (HEIGHT 480 WIDTH 640)
   is not of type
   SB-SYS:SYSTEM-AREA-POINTER.
   [Condition of type TYPE-ERROR]

и вот история, которая его вызвала (это произошло сразу после того, как я опубликовал prev. edit, так что в моем emacs все еще загружен код prev. edit s):

   CL-OPENCV> (defun get-size (arr)
    "Get the dimensions of the OpenCV array ARR. Return a size struct with the
  dimensions."
    (cffi:with-foreign-slots ((width height) (%get-size arr) (:struct cv-size))
      (make-size :width width :height height)))
  STYLE-WARNING: redefining CL-OPENCV:GET-SIZE in DEFUN
  GET-SIZE
  CL-OPENCV> 

   (defparameter img-size (make-size :width 640 :height 480))

  (defparameter img (create-image img-size +ipl-depth-8u+ 1))

  IMG
  CL-OPENCV> 

   (defparameter size (get-size img))


  The value (HEIGHT 480 WIDTH 640)
   is not of type
   SB-SYS:SYSTEM-AREA-POINTER.
   [Condition of type TYPE-ERROR]

Я понимаю это, потому что:

(defparameter size (get-size img)) 

обращается к вашему defun... я проследил это так, когда я просто бегу - показано с выводом:

CL-OPENCV> 
;; ;(cffi:foreign-type-size '(:struct cv-size)) = 8
(cffi:defcstruct cv-size
        (width :int)
        (height :int))

;; CvSize cvGetSize(const CvArr* arr)
 (cffi:defcfun ("cvGetSize" %get-size) (:struct cv-size)
  (arr cv-array))

STYLE-WARNING: redefining CL-OPENCV::%GET-SIZE in DEFUN
%GET-SIZE
CL-OPENCV> (defparameter capture (create-camera-capture 0))
CAPTURE
CL-OPENCV> (defparameter frame (query-frame capture))
FRAME
CL-OPENCV> 

(defparameter size (%get-size frame))
SIZE
CL-OPENCV> size
(HEIGHT 480 WIDTH 640)
CL-OPENCV> (cffi:with-foreign-slots ((width height) size (:struct cv-size))
        (list width height ))

я получаю ошибку:

The value (HEIGHT 480 WIDTH 640)
  is not of type
    SB-SYS:SYSTEM-AREA-POINTER.
     [Condition of type 

Я думаю, потому что выход вашего defcfun - это просто список, а with-foreign-slots нужен указатель

я запустил это:

(HEIGHT 480 WIDTH 640)
CL-OPENCV> (first size)
HEIGHT

проверить и его просто список

Кстати, я использовал эти функции для тестирования

(defparameter capture (create-camera-capture 0))

(defparameter frame (query-frame capture))

потому что у них более чистый вывод... create-image использует хакерство get-size, которое я изначально разместил вверху?

Я хотел бы использовать create-image и get-size без всех хакерских атак и просто использовать структуры для возвратов, чтобы я мог прекратить использовать make-size и сделать его более чистым... поэтому любой совет по этому поводу быть золотым... вот как я хотел бы создать create-image... я просто должен заставить его принять вывод из вашего (Rord's) defcfun... я сейчас пытаюсь включить ваш вывод defcfun ((HEIGHT 480 ШИРИНА 640)) до указателя... так он просто запустится в этом

;; IplImage* cvCreateImage(CvSize size, int depth, int channels)
(cffi:defcfun ("cvCreateImage" %create-image) ipl-image
  (size cv-size)
  (depth :int)
  (channels :int))

или все дело в том, что размер должен быть необходимостью...

Кроме того, я изменил Defun вы добавили в

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

и это работает сейчас... все еще любопытно, если я что-то напутал, и если бы ваш defun был бы лучше

РЕДАКТИРОВАТЬ!!!! Я ПОЛУЧИЛ ЭТО ВСЕ ФИГУРЫ!!!!!

here is the repl output :

; SLIME 2012-05-25
CL-OPENCV> ;; CvSize cvGetSize(const CvArr* arr)
(cffi:defcfun ("cvGetSize" get-size) (:pointer (:struct cv-size))
  (arr cv-array))
STYLE-WARNING: redefining CL-OPENCV:GET-SIZE in DEFUN
GET-SIZE
CL-OPENCV> ;; IplImage* cvCreateImage(CvSize size, int depth, int channels)
(cffi:defcfun ("cvCreateImage" create-image) (:pointer (:struct ipl-image))
   (size (:pointer (:struct ipl-image)))
  (depth :int)
  (channels :int))


STYLE-WARNING: redefining CL-OPENCV:CREATE-IMAGE in DEFUN
CREATE-IMAGE
CL-OPENCV> (defun detect-red-objects (&optional (camera-index 0))
   "Uses IN-RANGE-SCALAR to detect red objects"
  (with-capture (capture (create-camera-capture camera-index))
    (let ((window-name-1 "Video")
          (window-name-2 "Ball"))
           (named-window window-name-1)
           (named-window window-name-2)
           (move-window window-name-1 290 225)
           (move-window window-name-2 940 225)
      (do* ((frame (query-frame capture) (query-frame capture))
             (img (clone-image frame))
              (frame (clone-image img))
              (img-size (get-size frame))          
              (img-hsv (create-image img-size +ipl-depth-8u+ 3))
              (img-hsv-size (get-size img-hsv))
            (img-thresh (create-image img-hsv-size +ipl-depth-8u+ 1))
             (scalar-1 (make-cv-scalar 170.0 160.0 60.0))
             (scalar-2 (make-cv-scalar 180.0 256.0 256.0)))
         ((plusp (wait-key *millis-per-frame*)) nil)
             (smooth frame frame +gaussian+ 3 3)
             (cvt-color frame img-hsv +bgr2hsv+)
             (in-range-s img-hsv scalar-1 scalar-2 img-thresh)
             (smooth img-thresh img-thresh +gaussian+ 3 3)
             (show-image window-name-1 frame)
             (show-image window-name-2 img-thresh))
          (destroy-all-windows))))
DETECT-RED-OBJECTS

(the function detect-red-objects runs btw!...

РЕДАКТИРОВАТЬ!!!! Я ПОЛУЧИЛ ЭТО ВСЕ ФИГУРЫ!!!!!... Часть.... II - Еще лучше!

I messed up the struct on create-image the first time but it still ran...weird...but it runs when put the create-image struct back to cv-size....so no prob there...here is revised repl output


; SLIME 2012-05-25
CL-OPENCV> ;; CvSize cvGetSize(const CvArr* arr)
(cffi:defcfun ("cvGetSize" get-size) (:pointer (:struct cv-size))
  (arr cv-array))
STYLE-WARNING: redefining CL-OPENCV:GET-SIZE in DEFUN
GET-SIZE
CL-OPENCV> ;; IplImage* cvCreateImage(CvSize size, int depth, int channels)
(cffi:defcfun ("cvCreateImage" create-image) (:pointer (:struct ipl-image))
  (size (:pointer (:struct cv-size)))
  (depth :int)
  (channels :int))

STYLE-WARNING: redefining CL-OPENCV:CREATE-IMAGE in DEFUN
CREATE-IMAGE
CL-OPENCV> (defun detect-red-objects (&optional (camera-index 0))
   "Uses IN-RANGE-SCALAR to detect red objects"
  (with-capture (capture (create-camera-capture camera-index))
    (let ((window-name-1 "Video")
          (window-name-2 "Ball"))
           (named-window window-name-1)
           (named-window window-name-2)
           (move-window window-name-1 290 225)
           (move-window window-name-2 940 225)
      (do* ((frame (query-frame capture) (query-frame capture))
             (img (clone-image frame))
              (frame (clone-image img))
              (img-size (get-size frame))           
              (img-hsv (create-image img-size +ipl-depth-8u+ 3))
              (img-hsv-size (get-size img-hsv))
            (img-thresh (create-image img-hsv-size +ipl-depth-8u+ 1))
             (scalar-1 (make-cv-scalar 170.0 160.0 60.0))
             (scalar-2 (make-cv-scalar 180.0 256.0 256.0)))
         ((plusp (wait-key *millis-per-frame*)) nil)
             (smooth frame frame +gaussian+ 3 3)
             (cvt-color frame img-hsv +bgr2hsv+)
             (in-range-s img-hsv scalar-1 scalar-2 img-thresh)
             (smooth img-thresh img-thresh +gaussian+ 3 3)
             (show-image window-name-1 frame)
             (show-image window-name-2 img-thresh)) 
          (destroy-all-windows))))
DETECT-RED-OBJECTS

@Liam Edit

хорошо, я попробовал ваш метод translate-from-foreign, и он сработал, я определил их в моем файле structs.lisp

(cffi: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))))

и get-size и create-image определяются следующим образом

;; CvSize cvGetSize(const CvArr* arr)
 (cffi:defcfun ("cvGetSize" get-size) (:struct cv-size)
   (arr cv-arr))

 ;; IplImage* cvCreateImage(CvSize size, int depth, int channels)
 (cffi:defcfun ("cvCreateImage" %create-image) ipl-image
   (size :int64)
   (depth :int)
   (channels :int))

 (defun create-image (size depth channels)
   "Create an image with dimensions given by SIZE, DEPTH bits per
 channel, and CHANNELS number of channels."
   (let ((nsize (size->int64 size)))
     (%create-image nsize depth channels)))

вот определение размера->int64

  (DEFUN SIZE->INT64 (S) (+ (SIZE-WIDTH S) (ASH (SIZE-HEIGHT S) 32)))

но мне нравится идея иностранного переводчика

так что мне было интересно, если вы покажете мне, как сделать переведенную на иностранную версию приведенного ниже метода from, это действительно заставило бы мою библиотеку петь... Я собираюсь сделать полную оболочку cffi для opencv и gsll это gsl, так что это действительно помогло бы, чтобы это произошло быстрее.... Еще раз спасибо за вашу помощь на все это до сих пор

(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))))

3 ответа

Решение

Чтобы "загрузить систему cffi-libffi", вам нужно указать ее как зависимость в библиотеке .asd файл. (Примечание: cffi-libffi требует, чтобы libffi библиотеки C была установлена ​​в вашей системе.)

Чтобы иметь возможность использовать (:struct structure-name)необходимо сначала определить структуру с cffi:defcstruct, вот так (я буду предполагать, что здесь cffi:defcstruct, cffi:defcfun, а также cffi:with-foreign-slots импортируются в текущий пакет):

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

Вы можете использовать (:struct cv-size) в defcfun как это:

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

РЕДАКТИРОВАТЬ: Исправлено get-size для передаваемых по стоимости структур.

И, наконец, определить get-size как это:

(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))))

РЕДАКТИРОВАТЬ 2:

Если я правильно понимаю ответ Лиама, это как написать translate-from-foreign метод, так что он создает структуру напрямую, без создания промежуточного 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)))

Вам не нужно определять оба %get-size а также get-size, Вместо этого вы можете определить

(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))))

а затем определить функцию get-size непосредственно с defcfun,

Преимущество такого подхода заключается в том, что в любое время, когда у вас есть функция, которая возвращает размер cv, она будет автоматически переведена. И, если у вас есть сторонние функции, которым вы хотите передать размер cv, определите соответствующий метод для cffi: translate-into-foreign-memory. Вы также получите перевод автоматически, если вы используете mem-aref для указателя на структуру. Или, если вы вызываете cffi: convert-from-foreign.

В этом примере я использовал метод перевода по умолчанию; Вы можете, если хотите, напрямую обращаться к слотам без вызова (call-next-method).

(Кстати, причина, по которой у вас сложилось впечатление, что CFFI не может передавать структуры по значению, была в том, что он не мог до недавнего времени; cffi-libffi был представлен с выпуском 0.11.0.)

Вам просто нужно добавить :class xxx в cffi:defcstruct затем (cffi:defmethod translate-into-foreign-memory (object (type xxx) pointer) yyyy), он автоматически передаст структуру по значению сторонней функции!! Удивительно!!

А также (cffi:defmethod translate-from-foreign (pointer (type xxx)) zzzz) преобразует возвращенные данные структуры в данные lisp.

Более подробную информацию, пожалуйста, проверьте этот ответ также мной ^_^

Другие вопросы по тегам