|
Posted on 2012-07-11 16:43 点点滴滴 阅读(343) 评论(0) 编辑 收藏 引用 所属分类: 02 编程语言
lua_State Lua状态机或叫Lua虚拟机,支持多线程,可创建多个状态机 typedef int (*lua_Cfunction)(lua_State* L) Lua所调用的C函数的函数原型,在C程序中需要将这种函数类型的 函数注册到Lua状态机中,此后Lua才能调用到C的函数 如果有函数 int c_Hello(lua_State* l) { luaL_checktype(l, 1, LUA_TSTRING) luaL_checktype(l, 2, LUA_TSTRING) // 两个参数都是字符串 // 先输出第二个参数,后输出第一个参数 printf("%s\t%s\n", lua_tostring(l,-1),lua_tostring(l, -2)); }
需在C程序初始化的时候执行以下代码: // 将函数名压入LuaVM栈 lua_pushstring(l, "c_hello"); // 将函数地址压入LuaVM栈 lua_pushcclosure(l, &c_Hello, 0) // 把LuaVM栈上的这个表放入全局表中 lua_settable(l, LUA_GLOBALSINDEX) 此后在Lua中就可以这样调用: c_hello()
注:C函数的实现如果有参数的话最好为每一个参数进行类型检查 以确保所栈里的参数是函数参数类型匹配
lua_State* lua_newstate(lua_Alloc f, void* ud) 新建一个LuaVM,可以直接调用lua_open来调用这个函数
void lua_close(lua_State* l)) 关闭LuaVM
关于栈帧 当一个函数调用发生的时候就形成了一个栈帧,当这个函数调用结束 后这个栈帧就消失了
如在Lua这样调用c_hello("Hello", "World"),那么c_Hello所看到 栈帧就是从它的参数开始,如下图: 可以有两种索引方式对栈顶进行操作,正数和负数。
栈相关操作 int (lua_gettop) (lua_State *L) 取得当前使用了多少栈空间 void (lua_settop) (lua_State *L, int idx) 把栈顶设置在idx处,相当于做了一次函数调用改变了栈帧 如果这个时候调用 lua_settop(L, 1),则会把刚压入栈的两个参数删除 void (lua_pushvalue) (lua_State *L, int idx) 向此栈帧的第idx个位置的值压入栈顶,相当于复制 void (lua_remove) (lua_State *L, int idx) 删除第idx个位置的值 如果lua_remove(L, -2)则会将"Hello"删除而剩下"World"在栈顶 并会被移到原来"Hello"存放的位置 void (lua_insert) (lua_State *L, int idx); 先将整个上移或下移,并将栈顶的值压入空出的位置 void (lua_replace) (lua_State *L, int idx) 把栈顶的值替换掉idx处的值 int (lua_checkstack) (lua_State *L, int sz) 检查栈的大小是否已经增长到最大值,如果没有则将栈的大小增长sz 返回0表示栈溢出,返回1表示成功 void (lua_xmove) (lua_State *from, lua_State*to, int n) 从LavVM的栈顶移动n个值到to的LuaVM的栈顶
栈存取操作 以下函数往栈顶压入一个C值 void (lua_pushnil) (lua_State *L) 往栈顶压入一个NIL值 void (lua_pushnumber) (lua_State *L, lua_Number n) 往栈顶压入一个实数 void (lua_pushinteger) (lua_State *L,lua_Integer n) 往栈顶压入一个整数 void (lua_pushlstring) (lua_State *L, const char*s, size_t l) 往栈顶压入一个二进制串 void (lua_pushstring) (lua_State *L, const char*s) 往栈顶压入一个字符串 const char *(lua_pushvfstring) (lua_State *L,const char *fmt, va_list argp) 往栈顶压入一个格式化串,不过argp是变参 const char *(lua_pushfstring) (lua_State *L,const char *fmt, ...) 往栈顶压入一个格式化串 void (lua_pushcclosure) (lua_State *L,lua_CFunction fn, int n) 压入一个函数 void (lua_pushboolean) (lua_State *L, int b) 往栈顶压入一个bool类型 void (lua_pushlightuserdata) (lua_State *L, void*p) 往栈顶压入一个数组,数组的内存块指向p int (lua_pushthread) (lua_State *L)
以下函数往从栈中复制一个值存入栈顶 void (lua_gettable) (lua_State *L, int idx) idx指向表在栈中的位置,弹出栈顶的key取得表中的值并压入栈顶 此函数与lua_rawget的区别在于此函数会调用metatable的方法 void (lua_getfield) (lua_State *L, int idx,const char *k) 以k所在栈中的索引(idx)作为参数,取得k对应的值并压入栈顶 效率与lua_gettable相同 void (lua_rawget) (lua_State *L, int idx) idx指向表在栈中的位置,弹出栈顶的key取得表中的值并压入栈顶 为了提高数据访问的效率而直接读取表中的数据,不需要对metamethod的调用 这个函数在循环访问数组元素比较方便 void (lua_rawgeti) (lua_State *L, int idx, intn) idx指向表在栈中的位置,n指向key在栈中的位置,取得表中的值并入栈 相当于:lua_pushnumber(L,n);lua_rawget(L,idx) void (lua_createtable) (lua_State *L, int narr,int nrec) 新建一个表并压入栈顶,表的大小为narr,并预留了nrec个元素空间 void *(lua_newuserdata) (lua_State *L, size_t sz) 在栈中分配一块大小为sz的内存并把管理结构入栈且返回内存地址 int (lua_getmetatable) (lua_State *L, intobjindex) objindex指向对象在栈中的位置,取得对象的metatable并将其压入栈顶 如果失败或者对象没有metatable表则返回0 void (lua_getfenv) (lua_State *L, int idx) idx指向对象所在栈中的位置,取得此对象并将其环境量压入栈
以下函数用于判断栈内某处值的类型 int (lua_isnumber) (lua_State *L, int idx) 栈idx处的值是否是实数 int (lua_isstring) (lua_State *L, int idx) 栈idx处的值是否是字符串 int (lua_iscfunction) (lua_State *L, int idx) 栈idx处的值是否是函数 int (lua_isuserdata) (lua_State *L, int idx) 栈idx处的值是否是二进制数据 int (lua_type) (lua_State *L, int idx) 取得栈idx处的值的类型 const char *(lua_typename) (lua_State *L, inttp) 将类型转换成C字符串 int (lua_equal) (lua_State *L, int idx1, intidx2) 栈内两个值是否相等,类型和值都需要相等才返回真 int (lua_rawequal) (lua_State *L, int idx1, intidx2) 栈内两个对象是否相等,如果是对象时所指对象相同也算相等 int (lua_lessthan) (lua_State *L, int idx1, intidx2) 栈内两个值的大小,idx1处的值是否小于idx2处的值
以下函数将栈内的某个格转换成C能理解的值,栈结构不变 lua_Number (lua_tonumber) (lua_State *L, intidx) 将idx所指向的Lua值转换成实数返回 lua_Integer (lua_tointeger) (lua_State *L, intidx) 将idx所指向的Lua值转换成整数返回 int (lua_toboolean) (lua_State *L, int idx) 将idx所指向的Lua值转换成bool值返回 const char *(lua_tolstring) (lua_State *L, intidx, size_t *len) 将idx所指向的Lua值转换成字符串返回,并把长度存入len中 size_t (lua_objlen) (lua_State *L, int idx) 取得idx所指向的Lua值长度 lua_Cfunction (lua_tocfunction) (lua_State *L,int idx) 将idx所指向的Lua值转换成函数返回 void *(lua_touserdata) (lua_State *L, int idx) 将idx所指向的Lua值转换成内存块(数组)返回 lua_State *(lua_tothread) (lua_State *L, intidx) 将idx所指向的Lua值转换成LuaVM对象返回 const void *(lua_topointer) (lua_State *L, intidx) 取得idx所指对象的值的存储地址返回
以下函数与其对应的get函数类似 void (lua_settable) (lua_State *L, int idx) void (lua_setfield) (lua_State *L, int idx,const char *k) void (lua_rawset) (lua_State *L, int idx) void (lua_rawseti) (lua_State *L, int idx, intn) int (lua_setmetatable) (lua_State *L, intobjindex) int (lua_setfenv) (lua_State *L, int idx)
函数调用 关于函数调用 当需要调用一个Lua函数时,先要将函数压入栈中,然后将其参数依次压入 如下图:
假设在Lua代码中有函数: function hello(x, y) print(x, y) end 则在C中可以这样来调用: lua_getglobal(L, "hello"); -- 从全局域中取得hello函数并压入栈顶 lua_pushstring(L, "Hello"); -- 依次压入两个参数 lua_pushstring(L, "World"); lua_call(L, 2, 0); -- 跳过两个参数取得函数并调用此函数,函数中会取得相应参数 void (lua_call) (lua_State *L, int nargs, intnresults) 无保护的函数调用 nargs是指调用函数的参数个数,nresults是指所调用的函数的返回值个数 int (lua_pcall) (lua_State *L, int nargs, intnresults, int errfunc) 与lua_call相似,不过此函数是在保护模式下被调用 如果发生错误则会将错误压入栈,否则功能与lua_call一样 int (lua_cpcall) (lua_State *L, lua_CFunction func, void *ud) 直接调用一个C函数,并把ud做为func函数调用的参数 也就是说在func函数内部看来第一个参数是ud int (lua_load) (lua_State *L, lua_Reader reader,void *dt, const char *chunkname);
|