您好,欢迎访问三七文档
当前位置:首页 > 行业资料 > 国内外标准规范 > Lua API 小记
《LuaAPI小记》转载自RingOfTheC[ring.of.the.c@gmail.com]一、第一部分(API)这些东西是平时遇到的,觉得有一定的价值,所以记录下来,以后遇到类似的问题可以查阅,同时分享出来也能方便需要的人,转载请注明来自RingOfTheC[ring.of.the.c@gmail.com]打算记录一些lua_api,可能会觉得lua文档中已经说的很清楚了,但是我将用自己的方式,记录下我认为重要的东西,先约定一下api说明的格式编号.api作用简述api函数原型api操作说明返回值说明对栈的影响注意事项1.建一个新表voidlua_createtable(lua_State*L,intnarr,intnrec)创建一个新的table,并把它放在栈顶.narr和nrec分别指定该table的array部分和hash部分的预分配元素数量无返回值栈高度+1,栈顶元素是新table#definelua_newtable(L)lua_createtable(L,0,0)常用这个2.取表中的元素voidlua_getfield(lua_State*L,intindex,constchar*k)操作:arr=Stack[index]//arr肯定是表Stack.push(arr[k])取表中键为k的元素,这里的表是由index指向的栈上的一个表无返回值栈高度+1,栈顶元素是(Stack[index])[k]注意,该操作将触发__index元方法3.给表中的元素赋值voidlua_setfield(lua_State*L,intindex,constchar*k)操作:arr=Stack[index]arr[k]=Stack.top()Stack.pop()给表中键为k的元素赋值value(value就是栈顶元素),这里的表是由index指向的栈上的一个表无返回值栈高度-1,被弹出的是value注意,该操作将触发__newindex元方法4.取表元素和表元素赋值voidlua_gettable(lua_State*L,intindex)操作:ele=Stack[index]key=Stack.top()Stack.pop()value=ele[key]Stack.push(value)根据index指定取到相应的表;取栈顶元素为key,并弹出栈;获取表中key的值压入栈顶.无返回值栈高度不变,但是发生了一次弹出和压入的操作,弹出的是key,压入的是value注意,该操作将触发__index元方法voidlua_settable(lua_State*L,intindex)操作:ele=Stack[index]value=Stack.top()Stack.pop()key=Stack.top()Stack.pop()ele[key]=value根据index指定取到相应的表;取栈顶元素做value,弹出之;再取当前栈顶元素做key,亦弹出之;然后将表的键为key的元素赋值为value无返回值栈高度-2,第一次弹出value,第二次弹出key注意,该操作将触发__newindex元方法5.对table的一些操作[不引发原方法]voidlua_rawget(lua_State*L,intindex)和lua_gettable操作一样但是不触发相应的元方法voidlua_rawgeti(lua_State*L,intindex,intn)操作:ele=Stack[index]value=ele[n]Stack.push(value)无返回值栈+1,栈顶新增元素就是value不触发相应的元方法voidlua_rawset(lua_State*L,intindex)和lua_settable操作一样但是不触发相应的原方法voidlua_rawseti(lua_State*L,intindex,intn)操作:ele=Stack[index]value=Stack.top()Stack.pop()ele[n]=value无返回值栈-1,栈顶将value弹出不触发相应的元方法6.复制栈上元素并压入栈voidlua_pushvalue(lua_State*L,intindex)操作:value=Stack[index]Stack.push(value)无返回值栈+17.创建一个元表intluaL_newmetatable(lua_State*L,constchar*tname)操作:1.在注册表中查找tname,如果已经注册,就返回0,否者继续,并平栈lua_getfield(L,LUA_REGISTRYINDEX,tname)if(!lua_isnil(L,-1))return0;lua_pop(L,1);2.创建一个表,并注册,返回1lua_newtable(L)lua_pushvalue(L,-1)lua_setfield(L,LUA_REGISTRYINDEX,tname)return1有返回值栈+1,栈顶元素是在注册表中注册过的新表8.创建C值void*lua_newuserdata(lua_State*L,size_tsize)该函数分配一块由size指定大小的内存块,并放在栈顶返回值是新分配的块的地址栈+1,栈顶是userdatauserdata用来在lua中表示c中的值.一个完整的userdata有自己的元表,在垃圾回收时,可以调用它的元表的__gc方法9.注册c函数到lua中,其实没有这回事,lua中只有c闭包voidlua_pushcclosure(lua_State*L,lua_CFunctionfn,intn)向栈上压一个C闭包当一个c函数被创建时,可以绑定几个值在它上面,从而形成一个闭包.在任何时刻调用这个c函数时,都可以访问这几个绑定值.绑定的方法:先一次压入要绑定的n个值到栈上,然后调用lua_pushcclosure(L,fn,n)这样就形成的一个c闭包无返回值栈–(n-1),一共弹出n个元素(及那些绑定的值),压入一个cclosure#definelua_pushcfunction(L,f)lua_pushcclosure(L,f,0)#definelua_register(L,n,f)(lua_pushcfunction(L,f),lua_setglobal(L,n))没有返回值栈不变化这个是比较常用的,以n为lua中的key压入一个0个绑定值的cclosure.10.调用一个lua函数voidlua_call(lua_State*L,intnargs,intnresults)luacapi的特点就是不是一个人在战斗[我想表达的意思是,lua中的一句话,在capi实现起来就是n句,可能有人疑惑那为什么不直接用lua多好,capi这么麻烦,答案是有的事只能用capi才能实现],所以,调用它之前,需要布局一下栈,第一,要把要call的函数压入栈;第二,call要用的参数正序压入栈中;然后才能调用lua_call,调用完了,自己去取返回值,它都给你压栈上了.操作:argn=Stack.pop()...//一共压入nargs个参数arg2=Stack.pop()arg3=Stack.pop()func=Stack.pop()//函数本身也弹出res1,res2,...,resj=func(arg1,arg2,...,argn)Stack.push(res1)Stack.push(res2)…//压入nresults个返回值Stack.push(resj)无返回值调用结束后,栈高度增加nresults–(1+nargs),如果将nresults参数设置为LUA_MULTRET,那么lua返回几个值,栈上就压入几个值,否者强制压入nresults个值,不足的是空值,多余的抛弃掉注意,这个函数是有危险的,如果在其中发生了错误,会直接退出程序这个函数的用途:尚未发现,除非你能接受出错立马退出,反正我是做游戏的,我受不起,呵呵,顺便一说,lauxlib.h中的luaL_check*一族函数也是这样的,不符合预期的话,直接退出,这些函数都要小心,有类似于断言的效果.11.保护下调用一个lua函数intlua_pcall(lua_State*L,intnargs,intnresults,interrfunc)参数,行为和lua_call都一样,如果在调用中没有发生任何错误,lua_pcall==lua_call;但是如果有错误发生时,lua_pcall会捕获它errfunc指出了Stack上的一个元素,这个元素应该是一个函数,当发生错误的时候ef=Stack[errfunc]value=ef(errmsg)Stack.push(value)也就是说,在错误的时候,errfunc指定的错误处理函数会被调用,该处理函数的返回值被压到栈上.默认情况下,可以给errfunc传值0,实际的效果是指定了这样一个函数做出错处理functiondefaulterr(errmsg)returnerrmsgend.本函数有返回值LUA_ERRRUN运行时错误LUA_ERRMEM内存分配错误[注意,这种错会导致lua调用不了错误处理函数]LUA_ERRERR运行错误处理函数时出错了,写程序的时候必须检查返回值:)强烈推荐该函数,不过事实上大家也都用的这个函数:)12.保护下调用一个c函数intlua_cpcall(lua_State*L,lua_CFunctionfunc,void*ud)以保护模式调用c函数,func中可以且只能从堆栈上拿到一个参数,就是ud,当有错误时,和lua_pcall返回相同的错误代码,并在堆栈顶部留下errmsg字符串,调用成功的话它返回零,并且不会修改堆栈,所有从func中返回的值都被扔掉.这里注意的问题是:1.当有错误时,这个错误的意思是lua的错误,而不是c/c++的错误.在func中使用lua_call和lua_check*族函数,并不会导致程序退出了,而是表现的像lua_pcall那样.2.调用成功的时候func中的返回值都被扔掉了.二、第二部分(lua值,栈解释)1.理解lua的栈到底是什么?lua的栈类似于以下的定义,它是在创建lua_State的时候创建的:TValuestack[max_stack_len]//欲知内情可以查lstate.c的stack_init函数存入栈的数据类型包括数值,字符串,指针,talbe,闭包等,下面是一个栈的例子:执行下面的代码就可以让你的lua栈上呈现图中的情况lua_pushcclosure(L,func,0)//创建并压入一个闭包lua_createtable(L,0,0)//新建并压入一个表lua_pushnumber(L,343)//压入一个数字lua_pushstring(L,“mystr”)//压入一个字符串这里要说明的是,你压入的类型有数值,字符串,表和闭包[在c中看来是不同类型的值],但是最后都是统一用TValue这种数据结构来保存的:),下面用图简单的说明一下这种数据结构:TValue结构对应于lua中的所有数据类型,是一个{值,类型}结构,这就lua中动态类型的实现,它把值和类型绑在一起,用tt记录value的类型,value是一个联合结构,由Value定义,可以看到这个联合有四个域,先说明简单的p--可以存一个指针,实际上是lua中的lightuserdata结构n--所有的数值存在这里,不过是int,还是floatb--Boolean值存在这里,注意,lua_pushinteger不是存在这里,而是存在n中,b只存布尔gc--其他诸如table,thread,closure,string需要内存管理垃圾回收的类型都存在这里gc是一个指针,它可以指向的类型由联合体GCObject定义,从图中可以看出,有string,userdata,closure,table,proto,upvalue,thread从下面的图可以的得出如下结论:1
本文标题:Lua API 小记
链接地址:https://www.777doc.com/doc-1085025 .html