ffi

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!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章