openresty - luajit - continue、bit、ffi

2018-07-31 15:19:58

我们知道,openresty 使用的开发语言为 Lua,内置了 LuaJIT 解释器,速度比 Lua 官方解释器要快很多。

LuaJIT 基于 Lua 5.1,但在不破坏兼容性的前提下适当引入了一些 5.2 和 5.3 的语言特性,还提供了很多特别的优化和库,例如 table.new、bit、ffi。LuaJIT 是开源的,官网地址为 http://luajit.org

Lua 的基本语言及相关操作请参考 lua5.1 类目相关文章。

continue

Lua 语言不支持 continue 语法,有时候很不方便,好在 LuaJIT 加入了 Lua 5.2 的 goto 语句,变相的实现了 continue。goto 语句需要配合标签 ::label::使用,例如

--tmp.lua
for i=0,6,1 do
    if i<5 then
        goto continue
    else
        print(i)
    end
    ::continue::
end
[root@192 lua]# /usr/local/openresty/luajit/bin/luajit tmp.lua 
5
6

bit

LuaJIT 为 Lua5.1 增加了对于位的处理能力。

--tmp.lua
local bit = require("bit")

local x = 5  --101
local y = 7  --111

print(bit.band(x,y))  --&
print(bit.bor(x,y))   --|
print(bit.bnot(x))    --非~
print(bit.bxor(x,y))  --异或^

print(bit.lshift(x,1))  --左移1位
print(bit.rshift(x,1))  --右移1位
[root@192 lua]# /usr/local/openresty/luajit/bin/luajit tmp.lua 
5
7
-6
2
10
2

ffi

ffi 是 LuaJIT 里最强大也是最有价值的一个库,极大的简化了在 Lua 里调用 c/c++ 函数的工作,而且执行效率更高。

ffi 不仅可以调用系统函数和 openresty/nginx 内部的 C 函数,还可以加载 so 形式的动态库,调用动态库的函数,从而轻松扩展 Lua 的功能。

ffi.load       加载 *.so 动态库
ffi.null         相当于c的 NULL
ffi.string     把C指针指向的内存转化为 Lua 字符串
ffi.cdef       声明C的数据结构
ffi.typeof    声明一个 C 类型
ffi.new        利用上面的 C 类型分配内存
ffi.C            C函数所在的全局命名空间,可以用 . 来执行

local ffi = require("ffi")
ffi.cdef[[
int printf(const char *fmt, ...);
]]
ffi.C.printf("Hello %s!\n", "world")

在 Lua 里想要跟C交互的都是 cdata 类型

local ffi = require("ffi")
ffi.cdef[[
int printf(const char *fmt, ...);
]]

ffi.C.printf("直接打印失败   %d\n", 10)

--下面先生成 cdata 类型
--第一种
t1 = ffi.typeof("int")
local cint_a = ffi.new(t1, 10)

--第二种
local cint_b = ffi.new("int", 11)

--第三种
local cint_c = t1(12)

ffi.C.printf("第二种方式成功 %d %d %d\n", cint_a, cint_b, cint_c)
[root@192 lua]# /usr/local/openresty/luajit/bin/luajit tmp.lua 
直接打印失败   0
第二种方式成功 10 11 12

对于字符串,ffi.new 第一个参数只能是 const char *、const char[size] 或 char[size]。

local ffi = require("ffi")
ffi.cdef[[
int printf(const char *fmt, ...);
]]

local s_a = ffi.new("const char *", "http://www.freecls.com")

local s_b = ffi.new("char [5]", "hello")
local s_c = ffi.new("const char [5]", "hello")

ffi.C.printf("%s %s %s\n", s_a, s_b, s_c)

print(s_a)
print(ffi.string(s_a))
[root@192 lua]# /usr/local/openresty/luajit/bin/luajit tmp.lua 
http://www.freecls.com hello hello
cdata<const char *>: 0x4151b608
http://www.freecls.com

对于结构体,可以使用表格赋值

local ffi = require("ffi")
ffi.cdef[[
int printf(const char *fmt, ...);

struct son{
	int c;
	int d;
	const char *name;
};

struct person {
	int a;
	int b;
	
	struct son e;
};

struct eat{
	char *name;
	char sex[7];
};

]]

local ss = ffi.new("const char *", "freecls")
local p1 = ffi.new("struct person", {1,2,{3,4, ss}})

p1.e.name = "changed"

print(ffi.string(p1.e.name))


local p2 = ffi.new("struct eat")
p2.name = ffi.new("char[7]")
ffi.copy(p2.name, "freecls")
ffi.copy(p2.sex, "1234567")

print(ffi.string(p2.sex))

p2.sex = "3333333"

print(ffi.string(p2.sex))
[root@192 lua]# /usr/local/openresty/luajit/bin/luajit tmp.lua 
changed
1234567
3333333

加载外部动态库

//main.c
int add(int x, int y){
    return x + y;
}

int add1(int *x, int *y){
    return *x + *y;
}

接下来编译成动态库并拷贝到默认搜索路径,我的是 /lib64

gcc -g -fPIC -Wall main.c -shared -o libtest.so
cp libtest.so /lib64/

int 型指针可以用数组模拟

local ffi = require("ffi")

ffi.cdef[[
int add(int,int);
int add1(int *, int*);
]]

local test = ffi.load("test")
print(test.add(1,2))

local i1 = ffi.new("int[1]", 3)
local i2 = ffi.new("int[1]", {4})

print(test.add1(i1, i2))
[root@192 lua]# /usr/local/openresty/luajit/bin/luajit tmp.lua 
3
7

如果希望上面的库函数可以在 ffi.C 里调用,那么 load 第二个参数设为 true。

local ffi = require("ffi")

ffi.cdef[[
int add(int,int);
int add1(int *, int*);
]]

local test = ffi.load("test", true)
print(ffi.C.add(1,2))
[root@192 lua]# /usr/local/openresty/luajit/bin/luajit tmp.lua 
3

更多用法请参考 ffi tutorial


备注

1.测试环境centos7 64位,openresty 版本为 1.13.6.2。
2..原文地址http://www.freecls.com/a/2712/ec


©著作权归作者所有
收藏
推荐阅读
简介
天降大任于斯人也,必先苦其心志。