luajit FFI简单使用(1)

来源:互联网 发布:新开的淘宝店怎么升级 编辑:程序博客网 时间:2024/06/05 06:20

本文参考了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=10pos[0].y=10pos[1].x=500pos[1].y=300print(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])endlocal 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 pointlocal 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  4print(#a)        --> 5print(a:area())  --> 25local 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.
0 0