我想使用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输入也没有回来。
答案 0 :(得分:3)
如果你查看你的*inferior-lisp*
缓冲区,你会发现由于一些严重的内存损坏,SBCL已经进入了它的低级调试器。
struct stat
的具体布局在很大程度上取决于您拥有的架构。在我的64位Ubuntu 14.04上,以下似乎长度为144个字节,而您的定义只有52个字节长 - 难怪尝试写入它会导致内存损坏。
尝试为结构编写defcstruct
表单可能是一个坏主意,操作系统可以以任何方式自由定义结构。代码可以在您的计算机上运行,但如果他们使用不同的操作系统或处理器体系结构,可能不会在其他人的系统上运行 - 但如果您确实需要在系统上运行它,最简单的方法可能是写一个简短的C程序,转储屏幕上所有字段的大小和偏移量,然后从那里构建。
如果您需要编写在多个不同系统上运行且使用stat
的代码,一个很好的选择是自己在C中编写一个简单的代理模块,并使用一个定义良好的常量接口来调用{ {1}}代表你。这是我多次使用的方法,在C端保持外来物的安全,只在FFI上传递真正需要的数据。
对于更强大的CFFI定义,还有SWIG。
答案 1 :(得分:2)
@ 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))
请注意,对于'(:struct stat)
外国类型,它使用'(:pointer (:struct stat))
代替buf
。
我是如何得到正确的结构的?我想记录下来。
以下是我使用的最终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)
匹配。