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 Я уверен, что вы уже знали это, извините, что так долго, чтобы получить ответ. Надеюсь, это может помочь другим