Lua C Api lua_gettable 、lua_settable 、lua_next 使用详解

之前一直没理清lua_gettable和lua_settable的使用,今天理清了,顺便就做下笔记了。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.lua_next
int lua_next (lua_State *L, int index);

从栈上弹出一个 key(键),然后把索引指定的表中 key-value(健值)对压入堆栈(指定 key 后面的下一 (next) 对)。如果表中以无更多元素,那么lua_next 将返回 0 (什么也不压入堆栈)。

典型的遍历方法是这样的:

     /* table 放在索引 ‘t‘ 处 */
     lua_pushnil(L);  /* 第一个 key */
     while (lua_next(L, t) != 0) {
       /* 用一下 ‘key‘ (在索引 -2 处) 和 ‘value‘ (在索引 -1 处) */
       printf("%s - %s\n",
              lua_typename(L, lua_type(L, -2)),
              lua_typename(L, lua_type(L, -1)));
       /* 移除 ‘value‘ ;保留 ‘key‘ 做下一次迭代 */
       lua_pop(L, 1);
     }

在遍历一张表的时候,不要直接对 key 调用 lua_tolstring ,除非你知道这个 key 一定是一个字符串。调用 lua_tolstring 有可能改变给定索引位置的值;这会对下一次调用 lua_next 造成影响。

最后我们以一段c调用lua的loaded表并且设置符合某个规章的key将它的value设置为nil,为列:

 1 ua_getglobal(stack, "package");                         /* L: package,获得package,在栈定 */
 2 lua_getfield(stack, -1, "loaded");                       /* L: package loaded,获得表,在栈顶*/
 3 lua_pushnil(stack);                                     /* L: package loaded nil */
 4 while ( 0 != lua_next(stack, -2 ) ) /* L: package loaded, key, value,上一个栈顶为nil,弹出nil,获得表的第一个key和value,压入栈 */
 5 {
 6     //CCLOG("%s - %s \n", tolua_tostring(stack, -2, ""), lua_typename(stack, lua_type(stack, -1)));
 7     std::string key=tolua_tostring(stack, -2, "");  /*这时候栈顶得下一个,是key*/
 8     std::string tableKey =key;                      /*下面是对key的一段处理*/
 9     int found = tableKey.rfind(".lua");
10     if (found!=std::string::npos)
11         tableKey = tableKey.substr(0,found);
12     tableKey=replaceAll(tableKey,".","/");
13     tableKey=replaceAll(tableKey,"\\","/");
14     tableKey.append(".lua");
15     found = fileName.rfind(tableKey);
16     if (0 == found || ( found!=std::string::npos && fileName.at(found-1) == ‘/‘))
17     {
18         lua_pushstring(stack, key.c_str());  /*package loaded, key, value,newkey, 将key,压入栈顶*/
19         lua_pushnil(stack);                 /* pakage,loaded(table)(-5),key(-4),value(-3),key(-2),nil(-1)*/
20         if (lua_istable(stack, -5)) /*判读栈顶往下第五个是不是table*/
21         {
22             /*结果将key对应的值置为nil*/
23             lua_settable(stack, -5);/*pakage,loaded(table),key,value,  将栈顶两个元素作为key和value设置给table,弹出栈顶两个元素*/
24         }
25     }
26     lua_pop(stack, 1); /*pakage,loaded(table),key  弹出value,留下key作为下一个next*/
27 }
28 lua_pop(stack, 2); /*栈平衡*/
时间: 2024-10-16 16:14:18

Lua C Api lua_gettable 、lua_settable 、lua_next 使用详解的相关文章

Android基础入门教程——8.3.4 Paint API之—— Xfermode与PorterDuff详解(一)

Android基础入门教程--8.3.4 Paint API之-- Xfermode与PorterDuff详解(一) 标签(空格分隔): Android基础入门教程 本节引言: 不知道标题这两个玩意你熟不熟悉啦,如果自己实现过圆角或者圆形图片,相信对这两个名词 并不模式,一时半伙没想起来?没关系,下面这个图你可曾见过? PS:网上都说在:\samples\android-XX\legacy\ApiDemos\src\com\example\android\apis\graphics 下能找到这个

Android基础入门教程——8.3.7 Paint API之—— Xfermode与PorterDuff详解(四)

Android基础入门教程--8.3.7 Paint API之-- Xfermode与PorterDuff详解(四) 标签(空格分隔): Android基础入门教程 本节引言: 上节我们写了关于Xfermode与PorterDuff使用的第一个例子:圆角&圆形图片ImageView的实现, 我们体会到了PorterDuff.Mode.DST_IN给我们带来的好处,本节我们继续来写例子练练手, 还记得Android基础入门教程--8.3.2 绘图类实战示例给大家带来的拔掉美女衣服的实现吗? 当时我

Android基础入门教程——8.3.6 Paint API之—— Xfermode与PorterDuff详解(三)

Android基础入门教程--8.3.6 Paint API之-- Xfermode与PorterDuff详解(三) 标签(空格分隔): Android基础入门教程 本节引言: 上一节,我们学习了Xfermode中的三儿子:PorterDuffXfermode构造方法中的为一个参数: PorterDuff.Mode,我们在观看了16种图片混排模式后,又自己写代码来验证了一下文档中 18种不同的混排模式,18种是新增了ADD和OVERLAY两种模式!当然,仅仅验证知道是不够的, 本节我们来写个例子

Android基础入门教程——8.3.8 Paint API之—— Xfermode与PorterDuff详解(五)

Android基础入门教程--8.3.8 Paint API之-- Xfermode与PorterDuff详解(五) 标签(空格分隔): Android基础入门教程 本节引言: 好的,上一节中,我们又写了一个关于Xfermode图片混排的例子--擦美女衣服的Demo,加上前面的 利用Xfermode来实现圆角或圆形ImageView,相信大家对Xfermode已经不再像以前那么陌生了,或者 说有点熟悉了,嗯,本节我们来写Xfermode的最后一个例子,通过Xfermode的ProterDuff.

lua学习笔记16:table元表详解

一 table本质 Lua中table本质实际上是个类似HashMap东西. 其元素是很多的Key-Value对,类似iOS中的字典NSDictionary. 如果尝试访问了一个表中并不存在的元素时,就会触发Lua的一套查找机制. lua"面向对象"就是凭借这个机制实现的. 示例: local tab = {} print(tab.key) 输出:nil 因为tab中没有任何元素,当然视图访问其key元素时就会找不到,所以返回nil. 二 元表metatable 元表,即元素列表,是t

Lua中的模块与module函数详解

很快就要开始介绍Lua里的“面向对象”了,在此之前,我们先来了解一下Lua的模块. 1.编写一个简单的模块 Lua的模块是什么东西呢?通常我们可以理解为是一个table,这个table里有一些变量.一些函数… 等等,这不就是我们所熟悉的类吗? 没错,和类很像(实际上我说不出它们的区别). 我们来看看一个简单的模块,新建一个文件,命名为game.lua,代码如下: 复制代码代码如下: game = {}function game.play()    print("那么,开始吧");end

Lua中强大的元方法__index详解

今天要来介绍比较好玩的内容--__index元方法 1.我是备胎,记得回头看看 咳咳,相信每一位女生都拥有或者不知不觉中拥有了一些备胎,啊,当然,又或许是成为过别人的备胎. 没有备胎的人,就不是完整的人生.(小若:停!) 我们来想象一下,如果对一个table进行取值操作,但是table根本就没有这个值呢?比如: 复制代码代码如下: local t = {        name = "hehe",    }    print(t.money); 输出结果当然是:nil t只用于name

API HOOK及其注入技术详解

大家有没有想过,一些系统监控软件是如何得知我们所进行的操作的?杀软启发式分析是如何对病毒行为进行拦截和监控的?外挂又是如何读取到游戏的内部数据的?这些功能的实现,基本都有API HOOK存在.API HOOK分为ring0和ring3层,这里我们以ring3层API HOOK 进行讲解分析. API HOOK 在ring 3的实现,分为inline 和修改导入表2种方法,所谓inline,是指直接写入并覆盖函数开头字节汇编码的方法,这种方法有一个问题,便是他被杀软重点监控,成功率极低,而修改导入

【地图API】收货地址详解2

上次讲解的方法是: 在地图中心点添加一个标注,每次拖动地图就获取地图中心点,再把标注的位置设置为地图中心点.可参考教程:http://www.cnblogs.com/milkmap/p/6126424.html 可能有开发者觉得,这个算法会有“延时”,这次提供一个新的方法: 将一张标注图片始终固定在地图中央,不在地图上添加标注. 使用CSS将一张标注样子的图片,固定在地图中央. <style> #mapBox{height:400px;width:600px;position:absolute