编写C函数的技术-《lua程序设计》 27章 学习
1.数组操作
void lua_rawgeti(lua_State * L ,int index,int key)
void lua_rewseti(lua_State * L,int index,int key)
index表示table在栈的位置,key表示元素在table中的位置
test.lua内容
tab = {"a","b","c","c","e","f","g","h","i"} function ShowTable(tabb) print("显示table") for k,v in pairs(tabb) do print(v .. ' ') end end ShowTable(tab) print(GetTableFromIndex(tab,6)) SetTableFromIndex(tab,2,"aaaaaaaaaa") ShowTable(tab)
static int GetTableFromIndex(lua_State * L ) { //GetTableFromIndex(tab,6) int index = luaL_checkint(L,2); lua_rawgeti(L,1,index); const char * ret = luaL_checkstring(L,-1); return 1; } static int SetTableFromIndex(lua_State * L ) { //SetTableFromIndex(tab,2,"aaaaaaaaaa") int index = luaL_checkint(L,2); const char * szNewValue = luaL_checkstring(L,3); lua_pushstring(L,szNewValue); lua_rawseti(L,1,index); return 0; } int _tmain(int argc, _TCHAR* argv[]) { lua_State * L = luaL_newstate(); luaL_openlibs(L); lua_register(L,"GetTableFromIndex",GetTableFromIndex); lua_register(L,"SetTableFromIndex",SetTableFromIndex); if(0 != luaL_dofile(L,"test.lua")) { cout<<"error:"<<luaL_checkstring(L,-1)<<endl; lua_pop(L,1); } statckDump(L,"最后"); lua_close(L); system("pause"); return 0; }
2.字符串操作
lua_pushlstring(L,s+I,j-i+1) 把一个字符串区间为[I,j]传递给lua
下面函数将一个字符串以分隔符生成一个表 例如调用 split(“he,3,66,22”) 会返回table {“he”,”3”,”66”,”22”}
test.lua
tableStrings = l_split("1111,2222,3333,4444,6666",","); ShowTable(tableStrings)
static int l_split(lua_State * L ) { const char * s = luaL_checkstring(L,1); //第一个参数要分隔的字符串 const char * sep = luaL_checkstring(L,2); //第二个参数分隔符 const char * e; int i = 1; lua_newtable(L); //创建返回值 //遍历所有字符串分隔 while((e = strstr(s,sep)) != NULL) { lua_pushlstring(L,s,e-s); //压入子串 lua_rawseti(L,-2,i++); //修改table s = e + 1; //跳过分隔符 } //压入最后一个子串 lua_pushstring(L,s); lua_rawseti(L,-2,i); return 1; }
还有一些相关的函数 lua_pushfstring,luaL_buffinit,luaL_addchar,luaL_add 等lua帮助文件都有说明
3.在c函数中保存状态
对于一个lua函数 来说,有3种地方可以保存非局部数据他们是,全局变量,函数环境和非局部的变量(closure中)
3.1注册表
注册表是位于一个”伪索引“上,这个索引值由LUA_REGISTRYINDEX定义。伪索引就像一个栈中的索引,但它所关联的值不在栈中。为了获取注册表中的key为”Key”的值,可以这么做
lua_getfield(L,LUA_REGISTRYINDEX,”KEY”)
在注册表中为了避免冲突的key尽量不要用常用的名字,在注册表中不应使用数字类型的key,因为这种key是被”引用系统“所保留的,这个系统由辅助库中的一系列函数组成,它可以在向一个table存储value时忽略如何创建一个唯一 的key
int r = luaL_ref(L,LUA_REGISTRYINDEX); //弹出一个值,然后用新分配的整数key来将这个值保存到注册表中,最后返回这个key,这个key被称为”引用 “
lua_rewgeti(L,LUA_REGISTRYINDEX,r); //将与引用关联的值压入栈中
luaL_unref(L,LUA_REGISTRYINDEX,r); //释放该值和引用
3.2 C函数环境
lua5.1开始每一个c函数都有自己的一个环境table一个函数可以像访问注册表一样通过一个伪索引来访问他的环境table环境table的伪索引是LUA_ENVIRONINDEX。在在C语言中设置环境的代码如下:
int luaopen_foo(lua_State * L) { lua_newtable(L); lua_replace(L,LUA_ENVIRONINDEX); luaL_register(L,<库名>,<函数列表>); ... }
3.3 upvalue
注册表提供了全局变量的存储,环境提供了模块变量的存储,而upvalue机制则实现了一种类似于c语言中静态变量的机制。这种变量只在一个特定函数中可见。每当lua中创建一个函数时,都可以瘵任务数量的upvalue与这个函数关联
将这种c函数与upvalue关联称为closureg一个c closure类似于Lua closure。closure可以用同一个函数代码来创建多个closure,每个closre可以拥有不同的upvalue
static int counter(lua_State * L) { int val = lua_tointeger(L,lua_upvalueindex(1)); //luaj_upvalueindex可以生成一个upvalue的伪索引,注意这个索引可以像其它栈索引一样,但不存在于栈中 lua_pushinteger(L,++val); lua_pushvalue(L,-1); lua_replace(L,lua_upvalueindex(1)); //更新updavalue return 1; } int newCounter_(lua_State * L) { lua_pushinteger(L,0); //创建cclosure前必须将cclosure初始值压栈 lua_pushcclosure(L, //创建一个cclosure &counter, //基础函数 1); //upvalue个数 return 1; }