luajit ffi 小结

本文详细介绍了 LuaJIT 的 Foreign Function Interface (FFI) 库,包括如何引入 FFI 库,如何在 Lua 中调用 C 函数,以及如何处理 C 数据对象。通过 FFI,开发者可以方便地调用 C 标准库和自定义 C 函数,同时展示了如何创建和操作 cdata 对象,如基本类型、指针和结构类型。
摘要由CSDN通过智能技术生成

luajit ffi 小结


Lua 是一种语法简单,上手快的语言,虽然原生库比较少,但是可以方便的和 C 语言互相调用,常被用于脚本嵌入到 C 程序中。如 Redis 中可以加载 Lua 脚本,作用类似于存储过程,Nginx 中 lua-nginx-module 模块更是将 Lua 的这种特性发挥到极致。

使用 Lua 如何调用 C 的函数,个人认为是每一个 Lua 开发者必学的内容。Lua 调用 C 程序有两种方法,一种是使用 lua C API,另一种方法就是使用 luajit 提供的 ffi 库来调用 C 程序。本文主要是对 luajit ffi 的研究总结。

luajit ffi

luajit 和 lua 一样,是可以直接安装在操作系统中的,相关介绍直接参考官网 luajit。个人测试效果来看,luajit 的执行效率远高于 lua,大概是 8 倍左右。openresty 的 lua-nginx-module 模块就是将 luajit 集成到了 Nginx 中,实现在 Nginx 中执行 Lua 脚本

luajit ffi 是 luajit 提供给 Luaer 使用 Lua 调用 C 函数的 Lua 库,使用该库,Luaer 不用再去操作复杂的 Lua 栈来粘合两种程序代码,luajit ffi 官方资料

引入 luajit ffi 库

local ffi = require("ffi")

在 Lua 中调用 C 函数

和 lua 的 C API 一样,Lua 调用 C 函数,需要将 C 函数编译成链接库。区别在于 C API 查找 C 的 Lua 库是在 package.cpath 路径下进行查找,而这些库函数使用 Lua 栈接口进行编写。而 luajit 对于 C 链接库的引用遵从于普通 C 库的引用方式,先在 /usr/lib(/usr/lib64),/lib(/lib64) 目录下查找,再到用户自定义的 LD_LIBRARY_PATH 下查找。

  • 本节涉及接口:

    • ffi.cdef[[c_function define]]
    • ffi.C
    • ffi.load(name [,global])
  • 调用 C 标准库函数

    对于 C 标准库函数引用,需要引入函数,函数声明

    ffi.cdef[[c_function define]]
    

    调用 C 函数

    ffi.C.c_function
    

    如:

    local ffi = require("ffi")
    
    ffi.cdef[[
    int printf(const char *fmt, ...);
    int strcasecmp(const char *s1, const char *s2);
    ]]
    
    ffi.C.printf("Hello %s!\n", "world")
    ret = ffi.C.strcasecmp("Hello", "hello")
    print(ret)
    ret = ffi.C.strcasecmp("Hello", "hello1")
    print(ret)
    

    输出结果

    [root@AlexWoo-CentOS lua]# luajit ffic.lua 
    Hello world!
    0
    -49
    
  • 调用自定义的 C 函数

    调用自定义的 C 函数,首先要将自定义的 C 函数编译成链接库

    [root@AlexWoo-CentOS lua]# cat ffimyc.c 
    int add(int x, int y)
    {
        return x + y;
    }
    [root@AlexWoo-CentOS lua]# gcc -g -o libffimyc.so -fpic -shared ffimyc.c
    

    比调用 C 标准库函数,需要在 Lua 中引入相应的库

    ffi.load(name [,global])
    

    这里第二个参数如果为 true,则该库被引入全局命名空间,这里使用 ffi.load 需要注意两点:

    • 链接库文件必须在 C 的动态链接库查找路径中,否则会报类似错误:

### 回答1: 可以使用luajit ffi库的相关函数来读取文件路径下的文件名,以下是一个简单的示例代码: ``` local ffi = require("ffi") -- 定义readdir系统调用函数 ffi.cdef[[ typedef struct dirent { long d_ino; off_t d_off; unsigned short d_reclen; unsigned char d_type; char d_name[256]; } dirent; typedef struct DIR { int fd; dirent ent; } DIR; DIR *opendir(const char *name); dirent *readdir(DIR *dirp); int closedir(DIR *dirp); ]] -- 读取文件路径下的文件名 function list_files(path) local dir = ffi.C.opendir(path) local files = {} if dir ~= nil then repeat local entry = ffi.C.readdir(dir) if entry ~= nil then local name = ffi.string(entry.d_name) if name ~= "." and name ~= ".." then table.insert(files, name) end end until entry == nil ffi.C.closedir(dir) end return files end -- 测试 local files = list_files(".") for i, file in ipairs(files) do print(i, file) end ``` 在这个示例中,我们使用ffi.cdef()函数定义了readdir、opendir和closedir系统调用函数。接下来我们定义了一个list_files()函数,该函数使用opendir()函数打开指定路径下的目录,使用readdir()函数读取目录下的文件列表,并使用closedir()函数关闭目录。最后,我们遍历文件列表,将每个文件的文件名添加到一个数组中,并返回该数组。 要使用这个函数,只需将要读取的文件路径传递给list_files()函数,它将返回一个包含该目录下所有文件名的数组。在本例中,我们传递了"."作为路径,它将返回当前目录下的所有文件名。 ### 回答2: 在LuaJIT中使用ffi库读取文件路径下的文件名相对简单,只需要用到ffi库的C语言接口和Lua的文件操作函数就可以完成。以下是一个可以实现该功能的示例代码: ```lua local ffi = require("ffi") -- 定义C函数readdir实现读取文件路径下的文件名 ffi.cdef[[ typedef struct dirent { char d_name[256]; } dirent; typedef struct DIR DIR; DIR* opendir(const char* path); dirent* readdir(DIR* dirp); int closedir(DIR* dirp); ]] -- 定义读取文件路径下文件名的函数 function getFilenames(path) local dir = ffi.C.opendir(path) -- 打开目录 if dir == nil then return nil end local filenames = {} -- 存储文件名的数组 local entry = ffi.C.readdir(dir) -- 读取第一个文件 while entry ~= nil do local filename = ffi.string(entry.d_name) -- 转换为Lua字符串 if filename ~= "." and filename ~= ".." then table.insert(filenames, filename) -- 加入数组 end entry = ffi.C.readdir(dir) -- 读取下一个文件 end ffi.C.closedir(dir) -- 关闭目录 return filenames end -- 示例使用: local path = "./folder" -- 文件路径 local filenames = getFilenames(path) -- 获取文件名数组 if filenames == nil then print("无法打开目录") else for i, filename in ipairs(filenames) do print(filename) end end ``` 以上示例代码使用LuaJITffi库调用了C语言的函数opendir、readdir和closedir来实现读取文件路径下的文件名。首先,通过调用opendir打开指定路径的目录;然后使用readdir循环读取目录中的所有文件,并将文件名加入到一个Lua数组中;最后,调用closedir关闭目录并返回获取到的文件名数组。示例中也处理了当前目录(".")和上层目录(".. ")两个特殊文件名的情况。 你可以将示例代码保存在一个Lua文件中,并根据自己的实际需求修改文件路径,然后运行该Lua文件,即可看到打印出的文件名列表。 ### 回答3: 使用LuaJITffi库可以很方便地调用C函数,进而实现读取文件路径下的文件名的功能。下面是一个示例代码: ```lua -- 引入ffi库 local ffi = require("ffi") -- 定义C函数 ffi.cdef[[ typedef struct { void *d; } DIR; DIR *opendir(const char *filename); void closedir(DIR *dirp); const char *readdir(DIR *dirp); ]] -- 遍历文件路径下的文件名 function getFilenames(filepath) local dir = ffi.C.opendir(filepath) -- 打开目录 if dir ~= nil then local filenames = {} local dirent = ffi.C.readdir(dir) while dirent ~= nil do local name = ffi.string(dirent) -- 排除当前目录和上级目录 if name ~= '.' and name ~= '..' then table.insert(filenames, name) end dirent = ffi.C.readdir(dir) end ffi.C.closedir(dir) -- 关闭目录 return filenames end return nil end -- 测试 local path = "/path/to/directory" local filenames = getFilenames(path) if filenames ~= nil then for i, filename in ipairs(filenames) do print(filename) end else print("Failed to open directory") end ``` 上述代码首先使用ffi.cdef定义了C的DIR结构和相关函数,其中opendir用于打开目录,readdir用于读取目录中的文件名,closedir用于关闭目录。 然后,在getFilenames函数中,我们首先使用ffi.C.opendir打开指定的文件路径,然后循环使用ffi.C.readdir读取目录中的文件名,将有效的文件名加入到filenames表中,最后使用ffi.C.closedir关闭目录。 最后,在测试的部分,我们指定一个文件路径并调用getFilenames函数获取文件名列表,然后遍历打印每个文件名。如果无法打开目录,会打印"Failed to open directory"。 以上便是使用LuaJITffi库实现读取文件路径下的文件名的代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值