luajit FFI简单使用(1)

本文参考了luajit的官方文档编写。文档的结构也基本上是按照官网的来。

luajit FFI是一个简化的调用c库函数的途径。目的是简化lua和c语言之间调用的繁琐的push和pop。如果你已经有一个c语言编写的一个库了,可以不改代码的前提下,使用lua直接调用。

开胃菜

调用函数

先使用c编写一个工程,对外部提供一个函数

int c_add(int a, int b);

编写makefile将其编译成一个libc_utils.so库文件出来。
在lua中定义这个c函数并且加载这个so库。

local ffi = require("ffi")
ffi.cdef[[
int c_add(int a,int b);
]]
local cutils = ffi.load('libc_utils')
print(cutils.c_add(200,50))

如果是在windows版本上,可以直接来执行这个命令:

local ffi = require("ffi")
ffi.cdef[[
int MessageBoxA(void *w, const char *txt, const char *cap, int type);
]]
ffi.C.MessageBoxA(nil, "Hello world!", "Test", 0)

将会直接调出一个dialog出来。

使用数据结构

在c库里面定义计算向量相关的函数。我们在代码里面实现一个向量的点×

概念

点乘(Dot Product)
几何意义:
A·B = |A| |B| cos(θ).
θ是向量A和向量B见的夹角。
计算公式:
V1( x1, y1) V2(x2, y2) = x1*x2 + y1*y2

代码实现

typedef struct { uint8_t x, y; } position;
int dot_produce(position *a, position *b);
int dot_produce(position *a, position *b) {
    int ret = (a->x) * (b->x) + (a->y * b->y);
    return ret;
}

lua中调用


local ffi = require("ffi")
ffi.cdef[[
typedef struct { uint8_t x, y; } position;
int dot_produce(position *a, position *b);
]]
local cutils = ffi.load('libc_utils')
local pos = ffi.new("position[?]", 2)
pos[0].x=10
pos[0].y=10
pos[1].x=500
pos[1].y=300
print(cutils.dot_produce(pos[0],pos[1]))

进阶

调用zlib库

local ffi = require("ffi")
1 ffi.cdef[[
unsigned long compressBound(unsigned long sourceLen);
int compress2(uint8_t *dest, unsigned long *destLen,
          const uint8_t *source, unsigned long sourceLen, int level);
int uncompress(uint8_t *dest, unsigned long *destLen,
           const uint8_t *source, unsigned long sourceLen);
]]
2 local zlib = ffi.load(ffi.os == "Windows" and "zlib1" or "z")

local function compress(txt)
3  local n = zlib.compressBound(#txt)
  local buf = ffi.new("uint8_t[?]", n)
4  local buflen = ffi.new("unsigned long[1]", n)
  local res = zlib.compress2(buf, buflen, txt, #txt, 9)
  assert(res == 0)
5  return ffi.string(buf, buflen[0])
end

local function uncompress(comp, n)
  local buf = ffi.new("uint8_t[?]", n)
  local buflen = ffi.new("unsigned long[1]", n)
  local res = zlib.uncompress(buf, buflen, comp, #comp)
  assert(res == 0)
  return ffi.string(buf, buflen[0])
end

-- Simple test code.
local txt = string.rep("abcd", 1000)
print("Uncompressed size: ", #txt)
local c = compress(txt)
print("Compressed size: ", #c)
local txt2 = uncompress(c, #txt)
assert(txt2 == txt)

1.将zlib中的函数方法都定义到ffi接口中;
2.开始加载zlib库的C库文件;
3.通过compressBound函数估算压缩包结果的size;并且new一块n大小的内存。
4.新建一个unsigned long的变量用于提供给compress2函数中作为返回,压缩之后内存块的长度。
调用compress2函数,将内存块加压。
5.将返回的内存块通过ffi.string转换成lua中的内存块。
后面的是他的逆过程。

在这段代码里面还是演示了一些功能:
关于ffi.new的用法。这个里面都演示了如何创建一块buf,如何创建一块内存,并且得到他的地址。
关于ffi.string,这个模块是用于将内存块和lua的string做转换时使用。

为c类型绑定上元表

local ffi = require("ffi")
ffi.cdef[[
typedef struct { double x, y; } point_t;
]]

local point
local mt = {
  __add = function(a, b) return point(a.x+b.x, a.y+b.y) end,
  __len = function(a) return math.sqrt(a.x*a.x + a.y*a.y) end,
  __index = {
    area = function(a) return a.x*a.x + a.y*a.y end,
  },
}
point = ffi.metatype("point_t", mt)

local a = point(3, 4)
print(a.x, a.y)  --> 3  4
print(#a)        --> 5
print(a:area())  --> 25
local b = a + point(0.5, 8)
print(#b)        --> 12.5

这个就是在lua里面加载一个c语言的struct,并且在这个对象里面绑定上lua的实现方法。这个其实很奇妙的一个功能,今后如果一个c库,想做成面向对象就能通过这个调配一下就好了。
在官网中的解释

The C type metamethod mechanism is most useful when used in conjunction with C libraries that are written in an object-oriented style.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值