lua笔记

来源:互联网 发布:新手编程书 编辑:程序博客网 时间:2024/06/11 19:24

1.lua_gettable


void lua_gettable (lua_State *L, int index);

t[k] 值压入堆栈,这里的 t 是指有效索引 index 指向的值,而 k 则是栈顶放的值。这个函数会弹出堆栈上的 key,把结果放在栈上相同位置。

下面举个例子:

复制代码
// 将一个key放到栈顶,这个key为1。如果你的key是字符串,那就用lua_pushstring。lua_pushnumber(L, 1);// table一开始是在栈顶,即-1处的,但上面的语句压入了一个值,栈顶变-2了。// lua_gettable的作用就是以栈顶的值作为key来访问-2位置上的table。lua_gettable(L, -2);
复制代码

这时table中的第1个元素的值就放到栈顶了,你想怎么使用就怎么使用吧。

获取table元素:

  * 将元素的key压入到栈中,用 lua_gettable(Lua_state,index)

  * 对于字符串索引,可以用lua_getfield(Lua_state,index,key)来直接获取,

  如:lua_getfield(stack, -1, "loaded");等价于 lua_pushstring(L,"loaded") lua_gettable(L,-2);

上面说的是访问table中的一个元素的方法,那要怎么样遍历table中的所有元素呢?

1)如果table是一个以连续的整形作为key的table, 可以用下面方法:

复制代码
int size = lua_objlen(L,-1);//相关于#table  for(int i = 1; i <= size; i++)  {  lua_pushnumber(L, i);  lua_gettable(L, -2);  //这时table[i]的值在栈顶了  lua_pop(L, 1);//把栈顶的值移出栈,保证栈顶是table以便遍历。  };  
复制代码

2)如果table中的key是任意值呢?可以用下面的方法:

复制代码
lua_pushnill(L);  while(lua_next(L, -2))  {  //这时值在-1(栈顶)处,key在-2处。  lua_pop(L, 1);//把栈顶的值移出栈,让key成为栈顶以便继续遍历  }  
复制代码

这里重点说明一下lua_next。

它执行操作是这样的,以栈顶元素为key,先判断上一个key的值(这个值放在栈顶,如果是nil,则表示当前取出的是table中第一个元素的值),然后得到当前的key和value。

这时先把栈顶出栈,将新key进栈,后将value进栈。这样栈顶就是table中第一个遍历到的元素的值。用完这个值后,我们要把这个值出栈,让新key在栈顶以便继续遍历。当根据上一个key值算不出下一个key值时(其实这时候key的是多少并不重要,只要不为nil就行,因为为nil会返回table的第一个元素),lua_next返回0,结束循环。


2.lua_settable

void lua_settable (lua_State *L, int index);

作一个等价于 t[k] = v 的操作, 这里 t 是一个给定有效索引 index 处的值, v 指栈顶的值, 而 k 是栈顶之下的那个值。

这个函数会把键和值都从堆栈中弹出。

其实这个解释的意思就是,lua_settable 会把栈顶作为value,栈顶的下一个作为key设置到index指向的table,最后把这两个弹出弹出栈,这时候settable完成。

3:_G分析

  在Lua脚本层,Lua将所有的全局变量保存在一个常规的table中,这个table被称为全局环境,并且将这个table保存在一个全局变量_G中,也就是说在脚本中可以用_G获取这个全局table,并且有_G._G == _G,在默认情况,Lua在全局环境_G中添加了标准库比如math、函数比如pairs等。
lua_pushglobaltable把这个全局环境压入栈中,在lua5.2 该函数实质就是从注册表中获取这个全局环境,即lua_pushglobaltable用下面宏定义的: 
#define lua_pushglobaltable(L) lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS)
这里的LUA_REGISTRYINDEX是Lua注册表(注册表是lua虚拟机范围内是全局唯一的)的伪索引,LUA_RIDX_GLOBALS是全局环境在注册表中的索引(也就说,全局环境_G是虚拟机范围内是全局唯一的)。 

4:lua_pushliteral和lua_pushstring有何区别?

通常在push字符串字面值时使用lua_pushliteral,在push字符串指针是使用lua_pushstring。原因是前者通过sizeof(字符串字面值)/sizeof(char)计算长度,而后者通过strlen计算长度。因此前者只能push字符串字面值,但速度比后者快。而后者既可push字符串字面值,也可push字符串指针。

5:luaL_newmetatable

在lua代码中的普通表,不能作为userdata的metatable。必须使用luaL_newmetatable创建的表才能作为userdata的metatable。

6:向lua中注册c函数的过程是通过lua_pushcclosure(L, f, n)函数实现的

1. 创建一个 sizeof(CClosure) + (n - 1) * sizeof(TValue)大小的内存, 这段内存是 CClosure + TValue[n], 并做gc簿记[这点太重要了, 为什么lua要控制自己世界中的所有变量, 就是因为它要做gc簿记来管理内存],  isC= 1 标示其是一个C闭包.

2. c->f = f绑定c函数.    ---------  闭包.功能抽象 = f

3. env = 当前闭包的env[这说明了被创建的闭包继承了创建它的闭包的环境].  ----------- 闭包.env = env

4. 把栈上的n个元素赋值到c->upvalue[]数组中, 顺序是越先入栈的值放在upvalue数组的越开始位置, c- >nupvalues指定改闭包upvalue的个数.  ---------- 闭包.upvalue = upvalue

5. 弹出栈上n个元素, 并压入新建的Closure到栈顶.

0 0