gh-liu / myNote

0 stars 0 forks source link

`luajit`的`ffi`库 #13

Open gh-liu opened 4 months ago

gh-liu commented 4 months ago

luajit ffi

FFI 库允许在 Lua 代码里调用外部 C 函数并使用 C 数据结构 FFI 库很大程度上消除了用 C 编写繁琐的手动 Lua/C 绑定的需要(FFi库会解析C声明,也就是可以直接从C头文件中复制过来)

词汇:

  1. cdecl: C 类型声明(Lua 字符串)
  2. cdata: C 数据对象,保存相应ctype的值
  3. ctype: C 类型对象,由ffi.typeof()返回的特殊cdata,调用时以充当cdata的构造函数
  4. ct: C 类型,用于所有API
  5. cb: 回调对象,这是一个持有特殊函数指针的 C 数据对象,从 C 代码中调用此函数会运行对应的 Lua 函数
  6. VLA: 可变长度数组,数量使用 ? 声明,数量在创建时需给定
  7. VLS: 可变长度结构体,其最后一个元素是 VLA

声明和访问外部符号

ffi.cdef(def)

def 是一个 Lua 字符串,其必须是一系列 C 声明,通过分号隔开,单个声明的分号可以省略。

不支持任何预处理符号,除了#pragma pack

ffi.C

默认的 C 库命名空间。

与目标系统上的默认符号或库集绑定。这些符号或库与 C 编译器默认提供的符号或库大致相同,无需指定额外的链接库。

clib = ffi.load(name [,global])

加载按名称指定的动态库,并返回绑定到其符号的新 C 库命名空间。 在 POSIX 系统上,如果 global 为 true,则库符号也会加载到全局命名空间中。

如果 name 是路径,则从此路径加载库,否则,名称将以系统相关的方式规范化,并在动态库的默认搜索路径中搜索。 在 POSIX 系统上,如果名称不包含点,则会附加扩展名.so,此外如有必要,还会在前面添加lib前缀。因此 ffi.load("z") 在默认共享库搜索路径中查找“libz.so”。

创建 cdata 对象

-- 创建指定 ct 的 cdata 对象,VLA/VLS 类型需要指定 nelem
cdata = ffi.new(ct [,nelem] [,init...])

-- 为给定的 ct 创建一个 ctype 对象
ctype = ffi.typeof(ct)
-- 为给定的 ct 创建一个 ctype 对象并将其与元表关联
-- 仅允许结构/联合类型、复数和向量
-- 与元表的关联是永久性的,之后无法更改
ctype = ffi.metatype(ct, metatable)
-- 使用 ctype 作为构造函数
cdata = ctype([nelem,] [init...])

-- 为给定的 ct 创建标量 cdata 对象,使用 C 类型转换规则
cdata = ffi.cast(ct, init)

-- 将终结器与指针或聚合 cdata 对象关联
cdata = ffi.gc(cdata, finalizer)

C 类型信息

size = ffi.sizeof(ct [,nelem])
align = ffi.alignof(ct)
ofs [,bpos,bsize] = ffi.offsetof(ct, field)
status = ffi.istype(ct, obj)

工具函数

-- 返回由最后一个 C 函数调用设置的错误号,该错误号指示错误情况
err = ffi.errno([newerr])
-- 从 ptr 指向的数据创建一个内部 Lua 字符串
str = ffi.string(ptr [,len])
-- 将 src 指向的数据复制到 dst
ffi.copy(dst, src, [,len])
-- 用 len 个常量字节 c 填充 dst 指向的数据。
ffi.fill(dst, len [,c])

FFI Semantics