使用SBCL FFI传递和接收字符串

And*_*rei 3 lisp common-lisp

我有一个用优化的c(library.c)编写的复杂库:

#include <stdio.h>
#include "library.h"

void make_fullname(char* fullname, char* name, int version) {
  sprintf(fullname, "%s-%d", name, version);
  printf("lib-name: %s\n", name);
  printf("lib-fullname: %s\n", fullname);
}
Run Code Online (Sandbox Code Playgroud)

其中library.h包含

void make_fullname(char* fullname, char* name, int version);
Run Code Online (Sandbox Code Playgroud)

该库编译如下:

gcc library.c -o library.so -shared
Run Code Online (Sandbox Code Playgroud)

我试图从SBCL中使用它,这是我的最后一个(我放弃并转向stackoverflow):

(load-shared-object "library.so")

(define-alien-routine make_fullname void
  (fullname (c-string :external-format :ascii))
  (name (c-string :external-format :ascii))
  (x int))


(defun print-name-version (name version)
  (with-alien ((fullname (c-string :external-format :ascii)))
    (setf fullname (make-alien char 100))
    (setf fullname "dummy-string")
    (make_fullname fullname name version)
    (format t "~a~%" fullname)))
Run Code Online (Sandbox Code Playgroud)

在运行时,例如,(print-name-version"Program"1)我得到了这个

lib-name: Program
lib-fullname: Program-1
dummy-string
NIL
Run Code Online (Sandbox Code Playgroud)

所以,除了将字符串传递回lisp之外,一切都有效.这个例子中有什么不妥之处?谢谢,安德烈.

更新我已经让我的lisp代码工作,但我仍然不知道原始代码段失败的原因.这是一个有效的工作:

(defun print-name-version (name version)
  (let ((fullname (make-alien char 100)))
    (make_fullname fullname name version)
    (with-alien ((fn-str-repr (c-string :external-format :ascii) fullname))
      (format t "~a~%" fn-str-repr))
    (free-alien fullname)))
Run Code Online (Sandbox Code Playgroud)

Ram*_*ren 6

我从未使用过SBCL原生FFI绑定,但我想我已经弄明白了.为了将来参考,您将更有可能获得有关CFFI的帮助,而不是实现特定的FFI绑定.

当从Lisp代码访问时,外来类型c-string的变量自动转换为Lisp字符串.顶级函数make_fullname是Lisp代码,它fullname依次调用外部例程,但到那时已经转换为Lisp字符串,然后转换为新的 c字符串,一旦调用完成就会被丢弃.

您需要执行在编辑中执行的操作:分配存储缓冲区并将其传递给alien函数,并将关联的c-string变量视为该存储上的Lisp视图.