1、编写供lua调用的C函数
编写一个C函数返回一个table,简单示例代码如下:
//返回一个table
static int l_getmytable(lua_State * L)
{
lua_newtable(L);
char str[20] = {0};
for(int i = 1; i <= 10; i++)
{
lua_pushnumber(L,i);//相当于压入key
sprintf(str, "num is : %d", i);
lua_pushstring(L,str);//压入value
lua_settable(L, -3);//将前面的key和value都保存到table中
}
return 1;
}
//将l_getmytable函数公开给Lua
static void register_my_functions(lua_State* L)
{
lua_pushcfunction(L,l_getmytable);
lua_setglobal(L,"getmytable");
}
int main()
{
lua_State *ll = luaL_newstate();
luaL_openlibs(ll);
register_my_functions(ll);
luaL_dofile(ll, "call_C.lua");
lua_close(ll);
return 0;
}
在call_C.lua文件中调用getmytable函数如下:
local t = getmytable()
for k, v in pairs(t) do
print(k,v)
end
运行结果如下:
运行结果正常输出了一个table中的key和value。
2、编写一个供Lua调用的C模块。
在lualib项目下的源文件下找到init.c文件
在init.c中编写可供Lua调用的函数,简单示例代码如下:
//可供Lua调用函数1
static int showRlt1(lua_State * L)
{
lua_pushstring(L,"Im showRLT1");
return 1;
}
//可供Lua调用函数2
static int showRlt2(lua_State * L)
{
const char * value = luaL_checkstring(L, -1);
lua_pushstring(L,value);
return 1;
}
接着注册一下上面两个函数,实际上就是注册一个结构体数组mylibs(mylibs就是要供Lua调用的C模块):
static const luaL_Reg mylibs[] = {
{"rlt1",showRlt1},//showRlt1函数注册为rlt1,即在Lua中调用这个函数时使用人rlt1
{"rlt2",showRlt2},//showRlt2函数注册为rlt2,即在Lua中调用这个函数时使用人rlt2
{NULL,NULL}
};
利用上面的结构体数组创建lib:
int luaopen_my_lib(lua_State * L)
{
luaL_newlib(L,mylibs);
return 1;
}
然后再init.c文件的结构体数组loadedlibs中加入{"mylibs", luaopen_my_lib}一项:
最后重新生成lualib项目,以使新的模块加到lualib库中:
接下来是在Lua中调用mylibs模块,在call_C.lua文件中编写语句如下:
local mylib = require("mylibs")--引入mylibs模块
print(mylib)--实际结果为一个table
print(mylib.rlt1())--调用mylibs模块中的rlt1函数,实际调用的是init.c文件中的showRlt1函数
print(mylib.rlt2("chenzhenyong"))--调用mylibs模块中的rlt2函数,实际调用的是init.c文件中的showRlt2函数
运行程序,结果如下 :
3、Lua中的线程和状态
lua_State *ll = lua_newthread(luaState);//在当前线程中创建了一个新线程
//创建了新线程实际上就是在当前状态下创建了一个新状态。创建完的同时将子线程压入栈顶。
//最后将新线程即新状态返回
lua_pop(luaState, 0);//这会把栈顶的子线程弹出,之后子线程不在存在。
//注意子线程的创建依赖于现有的线程。
4、Lua中内存管理方式。Lua 对其内存具有严格控制,当关闭一个Lua状态时,Lua会显式地释放它的所有内存。如果加载了一个很大的Lua模块,并在之后删除了所有对它的引用,Lua最终会回收这个模块使用的所有没存。Lua通过一个“分配函数”来完成所有的你内存分配和释放,当用户创建一个Lua状态时,必须提供这个函数。
Lua中的垃圾回收器。从第一版到5.0版本,采用一种简单的“标记并清扫”垃圾收集器。Lua有时候会为了完成一个完整的垃圾收集周期而暂停与主程序的交互。每个垃圾收集周期分为4个阶段,标记、整理、清扫和收尾。
标记阶段:将所有可到达的对象都标记为活跃。
整理阶段:整理userdata。删除未被标记的key和value。
清扫阶段:遍历所有对象,未标记的就收集,已标记的就清除标记。
收尾阶段:更具整理阶段生成的userdata列表来调用它们的终结函数。
Lua5.1开始使用一种增量式的收集器,步骤与原收集器一样,但是它当的运行不会暂停整个程序的相应。它以隔行扫描的方式与解释器一起工作,每当解释器分配了一些固定的内存后,收集器就会运行一小步。在增量式的收集器中增加了原子操作。