Common lisp CFFI、回调和void*(如何在公共lisp/CFFI中创建指向本机对象的指针?)
假设我在C语言的一个物理库中有一个回调函数,它为两个相邻/接触的对象生成碰撞信息。这个回调使用一个(void*)数据参数,我想用它传入一个lisp对象 如何使用此(void*)参数?根据我的想法(我对CFFI比较陌生,但很快就掌握了窍门),我可以Common lisp CFFI、回调和void*(如何在公共lisp/CFFI中创建指向本机对象的指针?),common-lisp,Common Lisp,假设我在C语言的一个物理库中有一个回调函数,它为两个相邻/接触的对象生成碰撞信息。这个回调使用一个(void*)数据参数,我想用它传入一个lisp对象 如何使用此(void*)参数?根据我的想法(我对CFFI比较陌生,但很快就掌握了窍门),我可以 以某种方式将对象(CLOS对象)强制转换为指针,并将该指针传递给回调。我尝试了(cffi:convert to foreign my obj:pointer),但它只返回我的obj,而不是指针,我无法用它调用回调 围绕回调创建一个闭包,这样回调就可以引
(cffi:convert to foreign my obj:pointer)
,但它只返回我的obj,而不是指针,我无法用它调用回调有没有跨平台方式的想法?我知道很多C语言中的回调都使用void*参数,所以一定有人想到了这一点。我正在使用Clozure CL,但正如我所说,越是跨平台/跨实现越好。谢谢 我不确定这是否有效。如果GC移动您在闭包中捕获的对象,那将非常糟糕。也许你必须禁用GC。 也许可以选择从回调函数中调用另一个Lisp函数来设置变量,但为了实现这一点,Lisp函数的地址不应更改。我不知道lisp函数的地址是否会在垃圾收集期间或重新定义函数时发生更改 回调不可移植: 如果您的实现支持回调,则可以查看此处: 我修改了CFFI帮助中的一个示例。回调函数是比较运算符,它调用一个函数来打印它执行的每个比较。而不是打印列表Par,你可以把它推到一个全局变量(或闭包)。 请注意,我不相信这种用法是安全的。如果由于某种原因,存储在内存中的位置发生了变化,并且回调函数中的代码没有相应地更新,那么可能会导致不良结果
(require :cffi)
(defpackage :run
(:use :cl :cffi))
(in-package :run)
(defcfun "qsort" :void
(base :pointer)
(nmemb :int)
(size :int)
(fun-compar :pointer))
(defun store (par)
(format t "I'm comparing ~a~%" par))
(defcallback < :int ((a :pointer) (b :pointer))
(let ((x (mem-ref a :int))
(y (mem-ref b :int)))
(store (list x y))
(cond ((> x y) 1)
((< x y) -1)
(t 0))))
(with-foreign-object (array :int 10)
;; Initialize array.
(loop for i from 0 and n in '(7 2 10 4 3 5 1 6 9 8)
do (setf (mem-aref array :int i) n))
;; Sort it.
(qsort array 10 (foreign-type-size :int) (callback <))
;; Return it as a list.
(loop for i from 0 below 10
collect (mem-aref array :int i)))
我在freenode#lisp通道日志中搜索回调:
http://ccl.clozure.com/irc-logs/lisp/2010-04/lisp-2010.04.28.txt
Best comment there:
12:56:53 <pkhuong> and if you find out that threads are indeed an issue, I'd code a C wrapper to build a message queue.
对不起,如果我的回答有点晚,但我最近遇到了同样的问题。我使用的解决方案是使用整数键将回调要访问的所有lisp对象存储在哈希表中。然后我要做的就是将键传递给c函数,如果需要,将其转换为void* 这是有道理的(关于垃圾收集的注释)。我的实现确实支持回调。有没有办法将回调封装在闭包中,这样它就可以访问所需的数据,还是会受到相同问题的影响?我不明白调用另一个lisp函数来设置变量是什么意思。你能举个例子吗?@andrew实际上我刚刚意识到调用另一个lisp函数是愚蠢的。最好的办法是与freenode上的#lisp频道的人讨论这些问题。这本身就是一个好答案,我没有听说freenode上的lisp频道。现在我只有(defparameter my value nil),在调用回调之前将其设置为my object,回调可以很好地访问它。就像我说的,这样做会让我觉得很肮脏,但在我找到更好的方法之前,我必须这样做。谢谢你的帮助!至于GC部分:有一些FFI将锁定函数,但折衷的是,您必须显式释放它。在我看来,这是一个很好的折衷办法,因为我认为处理回调(通常)并不常见,而且可以创建closured回调(这是dope),这是有道理的。如果没有某种全局变量,似乎没有一个好的方法来实现它。我讨厌globals,但如果这是唯一的方法,那么好的文档和有限的使用就可以了。
http://ccl.clozure.com/irc-logs/lisp/2010-04/lisp-2010.04.28.txt
Best comment there:
12:56:53 <pkhuong> and if you find out that threads are indeed an issue, I'd code a C wrapper to build a message queue.
http://paste.lisp.org/display/98482
http://paste.lisp.org/display/98495