3

我想使用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 输入也不会返回。

4

2 回答 2

3

如果您查看您的*inferior-lisp*缓冲区,您会看到由于某些严重的内存损坏,SBCL 已进入其低级调试器。

的具体布局struct stat很大程度上取决于您拥有的架构。在我的 64 位 Ubuntu 14.04 上,以下似乎是 144 字节长,而您的定义只有 52 字节长 - 难怪尝试写入它会导致内存损坏。

尝试defcstruct为操作系统以任何它想要的方式自由定义的结构编写表单可能是一个坏主意。该代码可能在您的计算机上运行,​​但可能不会在其他所有人的系统上运行,如果他们使用不同的操作系统或处理器架构 - 但如果您真的需要让它只在您的系统上运行,最简单的方法可能是编写一个简短的 C 程序,将屏幕上所有字段的大小和偏移量转储,然后从那里开始构建。

stat如果您需要编写在多个不同系统上运行并且使用stat. 这是我多次使用的方法,在 C 端保持外来数据的安全,并且只通过 FFI 传递真正需要的数据。

对于更强大的 CFFI 定义,还有SWIG

于 2015-03-12T05:29:06.450 回答
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

sizeof(struct stat)在 C中匹配。

于 2015-03-12T09:21:26.287 回答