Common Lisp CFFI: указатель на указатель

Я пытаюсь написать оболочку CFFI для библиотеки CVDE Sundials. SWIG задыхался от заголовков Sundials, так как они довольно взаимосвязаны, и SWIG не мог найти правильные заголовки, поэтому я сделал это вручную: немного трудоемко, но я справился.

Сейчас я пытаюсь проверить, работает ли он правильно. Пока просто создаем "проблемный объект" и удаляем его. Вот где начинается проблема. Итак, "проблемный объект" выделяется через функцию

SUNDIALS_EXPORT void *CVodeCreate(int lmm, int iter);

Для которого я создал обертку:

(cffi:defcfun "CVodeCreate" :pointer
  (lmm :int)
  (iter :int))

PS. SUNDIALS_EXPORT (по крайней мере, в Unix) - это, по сути, ничто.

Теперь, чтобы уничтожить объект, Sundials использует свою собственную функцию:

SUNDIALS_EXPORT void CVodeFree(void **cvode_mem);

Итак, мне нужно передать ему ссылку на объект, созданный CVodeCreate, В С, если моя память не виновата, я бы сделал что-то вроде CVodeFree(&problem_object), В CL я написал эту обертку для функции:

(cffi:defcfun "CVodeFree" :void
  (cvode-mem :pointer))

Так вот COVDE-MEM это указатель на указатель Вопрос в том, как получить указатель указателя в CL/CFFI? Вот начало кода:

(defvar *p* (cvodecreate 1 2))

(PS. Не беспокойтесь о числах, переданных CVODECREATE, они просто сообщают, какие методы использовать, но все еще нуждаются в определенных константах, чтобы сделать его более читабельным)

Так *P* это что-то вроде

#.(SB-SYS:INT-SAP #X7FFFE0007060)

Если я передам это напрямую CVODEFREE, это заканчивается в ошибке:

CL-USER> (cvodefree *p*)
; Evaluation aborted on #<SIMPLE-ERROR "bus error at #X~X" {1005EC9BD3}>.

Я пытался пройти (CFFI:POINTER-ADDRESS *P*) но это приводит к подобной "ошибке шины..." (даже не уверен, что эта функция возвращает то, что мне нужно). Я также пытался сделать (CFFI:MAKE-POINTER (CFFI:POINTER-ADDRESS *P*))опять безуспешно.

Этот вопрос предлагает такой подход:

(cffi:with-foreign-object (p :pointer)
           (setf (cffi:mem-ref p :pointer) (cvodecreate 1 2))
           (cvodefree p))

Это работает (по крайней мере, это не выдает ошибку). Я думаю, что понимаю, как это работает: он создает (выделяет память) указатель на указатель P, чья MEM-REF (или в терминах C будет разыменование *p) заполняется результатом на CVODECREATE, Наконец, я передаю этот указатель на указатель на CVODEFREE, что ожидает именно этого. Наконец, память, выделенная для P освобождается после завершения формы. Это правильный подход? И это единственный, который я могу взять?

1 ответ

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

(let* (;; a float
       (v0 32s0)

       ;; a pointer to a float foreign memory
       (p0 (cffi:foreign-alloc :float :initial-element v0))) 

  ;; a new pointer
  (cffi:with-foreign-object (p1 :pointer)

    ;; make the new pointer point to the first pointer
    (setf (cffi:mem-aref p1 :pointer) p0)

    ;; dereferencing twice should give you the original number
    (cffi:mem-aref (cffi:mem-aref p1 :pointer) :float)))

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

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