ffi

本文详细介绍了LuaJIT的FFI库,包括如何调用C函数、处理复杂调用、使用C数据结构,以及在性能优化方面的权衡,如缓存策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

FFI

介绍

FFI 库,是 LuaJIT 中最重要的一个扩展库。它允许从纯 Lua 代码调用外部C函数,使用 C 数据结构

在 JIT 编译过的代码中,调用 C 函数,可以被内连处理,不同于基于 Lua/C API 函数调用。 说明FFI库比正常的LUA/C API调用高效很多。

使用

doc

调用C函数
local ffi = require("ffi")
ffi.cdef[[
int printf(const char *fmt, ...);
]]
ffi.C.printf("Hello %s!", "world")
  • 加载 FFI 库。
  • 为函数增加一个函数声明。这个包含在 中括号 对之间的部分,是标准C语法。
  • 调用命名的 C 函数——非常简单。

使用标准C库的命名空间 ffi.C。通过符号名 (“printf”) 索引这个命名空间,自动绑定标准 C 库。索引结果是一个特殊类型的对象,当被调用时,执行 printf 函数。传递给这个函数的参数,从 Lua 对象自动转换为相应的 C 类型。

复杂调用

ffi接口返回的是cdata类型的数据结构或者单位,Lua不能直接打印。

lua中的local str在ffi中默认的是string,如果要传递给c的函数参数,两种方式
a. c函数中使用const char *
b.
local text = "text"
local c_str = ffi.new("char[?]", #text)
ffi.copy(c_str, text)
lib.drawText(fb, px, py, c_str, color)

加载so
local zlib = ffi.load(ffi.os == "Windows" and "zlib1" or "z")
若A.so对B.so有依赖,则在A.so load前,先ffi.load("B", true),true表示加载到全局空间。


指针
ffi.new 返回的对应c里面的指针
返回的数值应该是地址,返回的应该是地址,但是是C


数组
local buf = ffi.new("uint8_t[?]", n)
? 表示可变数组
n 表示数组长度

返回的是一个int *的指针,相当于数组首地址


整数
local buflen = ffi.new("unsigned long[1]")

申请了一个字节的数组,类型是unsigned long*

传入null参数可以直接设置为nil


返回值

字符串
ffi.new("const char [?]", strnum)
申请了char *的数组

ffi.new("const char *[?]", strnum)

申请了可变长数组,长度为n
类型为 char **

ffi.string(buf, [buflen])
返回一个lua的string对象

如果buf为null,则会发生segfault
cdata的NULL对象可以用lua nil进行判断


For example:

a= some_c_data_which_is_NULL_pointer
print(a) -- prints cdata<somectype>: NULL
print(a == nil) -- it's true!! kind of useful…

-- and now, a very common Lua idiom, since a == nil...
print(a or "hello") -- guess what, it prints cdata<somectype>: NULL
print(ffi.string(a or "hello")) -- WTF! segmentation fault!!1!!eleven1!
print(ffi.string(a ~= nil a or "hello")) -- this one works, but unnecessarily 
verbose

使用C数据结构

openresty ffi

ffi.cdef [[
struct student {
int a,
char c,
} Stu;
]]

local stu = Stu(1,'c')

local stu = ffi.new("Stu",{1, 'c'})
idiom

如果要传递参数int *,需要在lua中先x=ffi.new(int[1]),x[0]=11

如果要传递char ,对于c读取lua字符串,可以直接传递lua字符串str=’abcd’。对于lua包含c返回char ,需要先申请str=ffi.new(“char “)

Idiom   C code  Lua code
Pointer dereference
int *p; x = *p;
*p = y; x = p[0]
p[0] = y
Pointer indexing
int i, *p;  x = p[i];
p[i+1] = y; x = p[i]
p[i+1] = y
Array indexing
int i, a[]; x = a[i];
a[i+1] = y; x = a[i]
a[i+1] = y
struct/union dereference
struct foo s;   x = s.field;
s.field = y;    x = s.field
s.field = y
struct/union pointer deref.
struct foo *sp; x = sp->field;
sp->field = y;  x = s.field
s.field = y
Pointer arithmetic
int i, *p;  x = p + i;
y = p - i;  x = p + i
y = p - i
Pointer difference
int *p1, *p2;   x = p1 - p2;    x = p1 - p2
Array element pointer
int i, a[]; x = &a[i];  x = a+i
Cast pointer to address
int *p; x = (intptr_t)p;    x = tonumber(
 ffi.cast("intptr_t",
          p))
Functions with outargs
void foo(int *inoutlen);    int len = x;
foo(&len);
y = len;    local len =
  ffi.new("int[1]", x)
foo(len)
y = len[0]
Vararg conversions
int printf(char *fmt, ...); printf("%g", 1.0);
printf("%d", 1);
    printf("%g", 1);
printf("%d",
  ffi.new("int", 1))
To Cache or Not to Cache

ffi需要缓冲空间而不是具体的函数,这是由于ffi的机制导致的。

local funca, funcb = ffi.C.funca, ffi.C.funcb – Not helpful!

local C = ffi.C – Instead use this!

local lib = ffi.load(…) – Instead use this!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值