cffi 函数调用挂起
cffi function call hangs
我想使用 Common Lisp 中的 stat(2)。
我已经定义了 stat
函数使用的结构:
(cffi:defctype mode_t :unsigned-int)
(cffi:defctype ino_t :unsigned-int)
(cffi:defctype dev_t :int)
(cffi:defctype nlink_t :int)
(cffi:defctype uid_t :unsigned-int)
(cffi:defctype gid_t :unsigned-int)
(cffi:defctype off_t :int)
(cffi:defctype time_t :long)
(cffi:defctype blksize_t :unsigned-int)
(cffi:defctype blkcnt_t :int)
(cffi:defcstruct stat
(st_dev dev_t)
(st_ino ino_t)
(st_mode mode_t)
(st_nlink nlink_t)
(st_uid uid_t)
(st_gid gid_t)
(st_rdev dev_t)
(st_size off_t)
(st_atime time_t)
(st_mtime time_t)
(st_ctime time_t)
(st_blksize blksize_t)
(st_blocks blkcnt_t))
函数本身:
(cffi:defcfun "stat" :int
(path :string)
(buf (:pointer (:struct stat))))
我试着这样称呼它:
(cffi:with-foreign-object (buf '(:pointer (:struct stat)))
(stat "/home/florian/tmp/msg.txt" buf)
(cffi:with-foreign-slots ((st_mode) buf (:struct stat))
st_mode))
史莱姆只是挂起。没有错误,REPL 输入没有返回。
如果您查看 *inferior-lisp*
缓冲区,您会发现由于一些严重的内存损坏,SBCL 已进入其低级调试器。
struct stat
的具体布局在很大程度上取决于您拥有的体系结构。在我的 64 位 Ubuntu 14.04 上,以下内容似乎有 144 个字节的长度,而您的定义只有 52 个字节长 - 难怪尝试写入它会导致内存损坏。
尝试为操作系统可以自由定义的结构编写 defcstruct
形式可能是个坏主意。该代码可能 运行 在您的计算机上,但可能不会 运行 在其他人的系统上,如果他们使用不同的 OS 或处理器架构 - 但如果您真的需要它运行仅在您的系统上,最简单的方法可能是编写一个简短的 C 程序,将所有字段的大小和偏移量转储到屏幕上,然后从那里构建。
如果您需要在多个不同的系统上编写 运行 并且使用 stat
的代码,一个不错的选择是自己用 C 编写一个简单的代理模块,具有定义明确的,常量接口,代表您调用 stat
。这是我在多个场合使用过的方法,在 C 端保证外来内容的安全,并且只通过 FFI 传递真正需要的数据。
对于更稳健的 CFFI 定义,还有 SWIG。
@jlahd 的回答帮助我找到了正确的解决方案。
找到正确的结构后,我的调用代码还是错了。这是最终代码:
(cffi:with-foreign-object (buf '(:struct stat))
(stat "/home/florian/tmp/msg.txt" buf)
(cffi:with-foreign-slots ((st_mode) buf (:struct stat))
st_mode))
请注意,对于 buf
外来类型,它使用 '(:struct stat)
而不是 '(:pointer (:struct stat))
。
我是如何得到正确的结构的?我想记录下来。
这是我使用的最终 cffi 结构:
(cffi:defcstruct (stat :size 144)
(st_mode :unsigned-int :offset 24))
这是我用来找出 stat
结构及其成员的大小和偏移量的 C 程序:
#include <stddef.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
int main (int argc, char* argv[])
{
struct stat foo;
printf("stat sizeof: %zu\n", sizeof(struct stat));
printf("st_mode sizeof: %zu\n", sizeof(foo.st_mode));
printf("st_mode offset: %zu\n", offsetof(struct stat, st_mode));
}
在我的电脑上,这给了我这个:
$ gcc stat.c
$ ./a.out
stat sizeof: 144
st_mode sizeof: 4
st_mode offset: 24
然后我可以检查 :unsigned-int
的大小是否为 4 个字节:
CL-USER> (cffi:foreign-type-size :unsigned-int)
4
并检查我的 cffi 结构的大小:
CL-USER> (cffi:foreign-type-size '(:struct stat))
144
在 C.
中匹配 sizeof(struct stat)
我想使用 Common Lisp 中的 stat(2)。
我已经定义了 stat
函数使用的结构:
(cffi:defctype mode_t :unsigned-int)
(cffi:defctype ino_t :unsigned-int)
(cffi:defctype dev_t :int)
(cffi:defctype nlink_t :int)
(cffi:defctype uid_t :unsigned-int)
(cffi:defctype gid_t :unsigned-int)
(cffi:defctype off_t :int)
(cffi:defctype time_t :long)
(cffi:defctype blksize_t :unsigned-int)
(cffi:defctype blkcnt_t :int)
(cffi:defcstruct stat
(st_dev dev_t)
(st_ino ino_t)
(st_mode mode_t)
(st_nlink nlink_t)
(st_uid uid_t)
(st_gid gid_t)
(st_rdev dev_t)
(st_size off_t)
(st_atime time_t)
(st_mtime time_t)
(st_ctime time_t)
(st_blksize blksize_t)
(st_blocks blkcnt_t))
函数本身:
(cffi:defcfun "stat" :int
(path :string)
(buf (:pointer (:struct stat))))
我试着这样称呼它:
(cffi:with-foreign-object (buf '(:pointer (:struct stat)))
(stat "/home/florian/tmp/msg.txt" buf)
(cffi:with-foreign-slots ((st_mode) buf (:struct stat))
st_mode))
史莱姆只是挂起。没有错误,REPL 输入没有返回。
如果您查看 *inferior-lisp*
缓冲区,您会发现由于一些严重的内存损坏,SBCL 已进入其低级调试器。
struct stat
的具体布局在很大程度上取决于您拥有的体系结构。在我的 64 位 Ubuntu 14.04 上,以下内容似乎有 144 个字节的长度,而您的定义只有 52 个字节长 - 难怪尝试写入它会导致内存损坏。
尝试为操作系统可以自由定义的结构编写 defcstruct
形式可能是个坏主意。该代码可能 运行 在您的计算机上,但可能不会 运行 在其他人的系统上,如果他们使用不同的 OS 或处理器架构 - 但如果您真的需要它运行仅在您的系统上,最简单的方法可能是编写一个简短的 C 程序,将所有字段的大小和偏移量转储到屏幕上,然后从那里构建。
如果您需要在多个不同的系统上编写 运行 并且使用 stat
的代码,一个不错的选择是自己用 C 编写一个简单的代理模块,具有定义明确的,常量接口,代表您调用 stat
。这是我在多个场合使用过的方法,在 C 端保证外来内容的安全,并且只通过 FFI 传递真正需要的数据。
对于更稳健的 CFFI 定义,还有 SWIG。
@jlahd 的回答帮助我找到了正确的解决方案。
找到正确的结构后,我的调用代码还是错了。这是最终代码:
(cffi:with-foreign-object (buf '(:struct stat))
(stat "/home/florian/tmp/msg.txt" buf)
(cffi:with-foreign-slots ((st_mode) buf (:struct stat))
st_mode))
请注意,对于 buf
外来类型,它使用 '(:struct stat)
而不是 '(:pointer (:struct stat))
。
我是如何得到正确的结构的?我想记录下来。
这是我使用的最终 cffi 结构:
(cffi:defcstruct (stat :size 144)
(st_mode :unsigned-int :offset 24))
这是我用来找出 stat
结构及其成员的大小和偏移量的 C 程序:
#include <stddef.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
int main (int argc, char* argv[])
{
struct stat foo;
printf("stat sizeof: %zu\n", sizeof(struct stat));
printf("st_mode sizeof: %zu\n", sizeof(foo.st_mode));
printf("st_mode offset: %zu\n", offsetof(struct stat, st_mode));
}
在我的电脑上,这给了我这个:
$ gcc stat.c
$ ./a.out
stat sizeof: 144
st_mode sizeof: 4
st_mode offset: 24
然后我可以检查 :unsigned-int
的大小是否为 4 个字节:
CL-USER> (cffi:foreign-type-size :unsigned-int)
4
并检查我的 cffi 结构的大小:
CL-USER> (cffi:foreign-type-size '(:struct stat))
144
在 C.
中匹配sizeof(struct stat)