Lua ffi
所有传递到lua的变量都必须在C里定义全局变量:
ffi.cdef[[ --[]数组变量大小可以不填
int n[]; --定义一个全局变量,才能传递
int num; --数值
int str[]; --字符串、数组都是这种
]]
关于C头文件:
#include <stdio.h> --使用 printf 函数必须加
#include <string.h> --使用 strcpy 函数必须加
实例:
Lua传参到C,并修改后返回:
--myffi.c
#include <string.h>
#include <stdio.h>
char str(char* L)
{
printf("string=%s\n",L);
printf("string*=%p\n",L);
strcpy(L,"abc "); --修改字符串 需要#include <string.h>
return 0;
}
int num(int L)
{
printf("number=%d\n",L);
printf("number*=%p\n",L);
int b = 2200;
return L+b;
}
--hello.lua
local ffi=require"ffi"
local myffi = ffi.load('myffi')
ffi.cdef[[
char str(char* L);
int num(int L);
]]
local a="人鱼"
local b=1100
--传入地址
-- local p = ffi.cast('char*', a)
-- myffi.str(p)
-- print("a="..a)
-- local p = ffi.cast('int', b)
-- b=myffi.num(p)
-- print(b)
linux编译:
gcc -g -o myffi.so -fpic -shared myffi.c
win系统
gcc -m32 -g -o myffi.dll -fpic -shared myffi.c
环境变量(遇到ffi.load报错需要设置):
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:your_lib_path
运行:
./lua-5.1.5/src/lua hello.lua
C++例子
//myffi.cpp
#include <iostream>
using namespace std;
int main()
{
cout << "Hello, world111111111111!" << endl;
return 0;
}
//hello.lua
local ffi=require"ffi"
local myffi = ffi.load('myffi')
ffi.cdef[[
int main();
]]
myffi.main()
编译
g++ -m32 -g -o myffi.dll -fpic -shared myffi.cpp
C传参到Lua:
--lua
local ffi=require"ffi"
local myffi = ffi.load('myffi')
ffi.cdef[[
char a[]; --C语言里面全局变量,才可以返回值
char* str(); --字符串返回指针
int b; --C语言里面全局变量,才可以返回值
int num(); --数值直接返回
]]
a=myffi.str()
print(ffi.string(a)) --类型cdata 指针 转换成 String
b=myffi.num()
print(b)
--c
char a[]="abcdef";
char* str()
{
printf("string=%s\n",a);
return a;
}
int b;
int num()
{
b=20000;
printf("number=%d\n",b);
return b;
}
C数组传到lua:
--lua
local ffi=require"ffi"
local myffi = ffi.load('myffi')
ffi.cdef[[
int n[]; --定义一个全局变量数组,才能传递
int main ();
int add(int *l);
]]
myffi.main()
myffi.add(myffi.n)
#include <stdio.h>
int n[ 5390*9590 ]; /* n 是一个包含 10 个整数的数组 */
int main ()
{
int i;
/* 初始化数组元素 */
for ( i = 0; i < 5390*9590; i++ )
{
n[ i ] = i + 100; /* 设置元素 i 为 i + 100 */
}
/* 输出数组中每个元素的值 */
return 0;
}
int add(int *l)
{
int j;
for (j = 0; j < 10; j++ )
{
printf("Element[%d] = %d\n", j, l[j] );
}
return 0;
}
延时函数
local ffi=require"ffi"
ffi.cdef[[
void Sleep(int ms);
int poll(struct pollfd *fds, unsigned long nfds, int timeout);
]]
local sleep
if ffi.os == "Windows" then
function sleep(s)
ffi.C.Sleep(s*1000)
end
else
function sleep(s)
ffi.C.poll(nil, 0, s*1000)
end
end
print(ffi.os)
for i=1,160 do
io.write("."); io.flush()
sleep(0.01)
end
io.write(".")
表初始化器
local ffi = require("ffi")
ffi.cdef[[
struct foo { int a, b; };
union bar { int i; double d; };
struct nested { int x; struct foo y; };
]]
ffi.new("int[3]", {}) --> 0, 0, 0
ffi.new("int[3]", {1}) --> 1, 1, 1
ffi.new("int[3]", {1,2}) --> 1, 2, 0
ffi.new("int[3]", {1,2,3}) --> 1, 2, 3
ffi.new("int[3]", {[0]=1}) --> 1, 1, 1
ffi.new("int[3]", {[0]=1,2}) --> 1, 2, 0
ffi.new("int[3]", {[0]=1,2,3}) --> 1, 2, 3
ffi.new("int[3]", {[0]=1,2,3,4}) --> error: too many initializers
ffi.new("struct foo", {}) --> a = 0, b = 0
ffi.new("struct foo", {1}) --> a = 1, b = 0
ffi.new("struct foo", {1,2}) --> a = 1, b = 2
ffi.new("struct foo", {[0]=1,2}) --> a = 1, b = 2
ffi.new("struct foo", {b=2}) --> a = 0, b = 2
ffi.new("struct foo", {a=1,b=2,c=3}) --> a = 1, b = 2 'c' is ignored
ffi.new("union bar", {}) --> i = 0, d = 0.0
ffi.new("union bar", {1}) --> i = 1, d = ?
ffi.new("union bar", {[0]=1,2}) --> i = 1, d = ? '2' is ignored
ffi.new("union bar", {d=2}) --> i = ?, d = 2.0
ffi.new("struct nested", {1,{2,3}}) --> x = 1, y.a = 2, y.b = 3
ffi.new("struct nested", {x=1,y={2,3}}) --> x = 1, y.a = 2, y.b = 3
参数化类型
为了促进某些抽象,两个函数 ffi.typeof和 ffi.cdef支持C声明中的参数化类型。注意:使用cdecl的其他API函数均不允许这样做。
您可以在声明中写typedef名称, 标识符或数字的任何地方,都可以改写 $(美元符号)。这些占位符按出现顺序替换为cdecl字符串后的参数:
--声明具有参数化字段类型和名称的结构:
ffi.cdef([[
typedef struct { $ $; } foo_t;
]], type1, name1)
--具有动态名称的匿名结构:
local bar_t = ffi.typeof("struct { int $, $; }", name1, name2)
--派生的指针类型:
local bar_ptr_t = ffi.typeof("$ *", bar_t)
--即使在VLA不起作用的地方,参数化尺寸也可以工作:
local matrix_t = ffi.typeof("uint8_t[$][$]", width, height)
cdata对象的垃圾收集
请注意,指针本身是cdata对象,但是垃圾收集器不会跟随它们。因此,例如,如果将cdata数组分配给指针,则只要指针仍在使用中,就必须保持持有该数组的cdata对象处于活动状态:
ffi.cdef[[
typedef struct { int *a; } foo_t;
]]
local s = ffi.new("foo_t", ffi.new("int[10]")) -- 错误!
local a = ffi.new("int[10]") -- OK
local s = ffi.new("foo_t", a)
-- 现在对's'进行操作,但保持'a'存活直到完成。
—C语言里,只能储存数值,所以任何类型都转成地址,再传到C函数里,读取数组里的地址来获取其他数组内容。
a = ffi.new("char[100]",'daslkhdasl') --char a[100]='daslkhdasl'
c = ffi.new("char[100]", 'nnncncncncc')
--c = ffi.new("char[100]", {'n','n','n','\0'}) --字符串
--c = ffi.new("int[100]", {1,2,3,4,5}) --数值
local p = ffi.cast('char*', a) -- char *p = a[100] 转指针
local p1 = ffi.cast('char*', c)
b = ffi.new("int[100]", {tonumber(p),tonumber(p1)}) --储存 a[100] 指针地址
myffi.main(b)
#include <stdint.h> --解决警告:将一个整数转换为大小不同的指针 调用 uintptr_t 类型
int main(int *a) {
printf("%s\n",a[1]); --读取地址 输出 'nnncncncncc'
--int *p =(int *)(uintptr_t)a[1]; --uintptr_t是解决警告,数值 转 指针用
--printf("%s\n",p[1]); --读取地址 输出 2
return 0;
}
local diff={"0x000400-0x333333", "0x000400-0x333333"}
local t ={}
for k,v in pairs(diff) do
if type(v)=="string" then
local p = ffi.cast('char*', ffi.new("char[100]",v))
table.insert(t,tonumber(p))
end
end
local b = ffi.new("int[100]", t)
--b = {地址1,地址2}
c y=0, x=0
yx距离+x
_BINARIZE_Image[(yrect[2]-rect[0])+x]
lua 一维表转二维表 i=一维表第n个
y=取整(i/x距离)+1,x=x
ti[math.floor(i/(rect[3]-rect[1]))+1][x]
-- logcat(ffi.string(libhello.str)) --需要转换才能提取c文件里的字符串
/* int diff1[]={10,11,10111}; //一维表
int diff2[]={12,13,10222};
int diff3[]={14,15,10333};
+
unsigned int p1 = (unsigned int)diff1; //把指针转为数值,存入数据到数组
unsigned int p2 = (unsigned int)diff2;
unsigned int p3 = (unsigned int)diff3; */
/* for(y = rect[1]; y<rect[3]+1; y++) { //遍历图片指定范围像素点
for(x = rect[0]; x<rect[2]+1; x++) {
printf("%d,%d\r\n",x,y);
int co,ko,s;
co=16711935; //当前颜色值
ko=-5919833; //开发颜色值
s = 12; //相似度阈值
if (get_color_PK(str1,str_num1,co,ko,s)==0) { //比色 0成功 -1失败
printf("匹配\r\n");
}
}
} */
不明觉厉。。