C中的lua二维表遍历

#C中的lua二维表遍历

#一、 主要内容

  1. lua中二维表的表示
  2. C API 的使用
    • 打开lua
    • 关闭lua
    • main
  3. C中的遍历函数
    • lua和C中的虚拟栈
  4. 运行结果
  5. 遇到的错误使用的例子

#二、lua中的二维表表示
lua代码

01.#! /usr/bin/lua  
02.  
03.cmdlist=  
04.{  
05.        {  
06.                send="w 0x0000 0x0001",  
07.                plain="???",  
08.                dalay=2 --[[ms]]  
09.        },  
10.  
11.        {         
12.                send="w 0x0000 0x0002",  
13.                plain="???",  
14.                dalay=2 --[[ms]]  
15.        },  
16.  
17.        {  
18.                send="w 0x0000 0x0003",  
19.                plain="???",  
20.                dalay=2 --[[ms]]  
21.        },  
22.  
23.        {  
24.                send="w 0x0000 0x0004",  
25.                plain="???",  
26.                dalay=2 --[[ms]]  
27.        },  
28.  
29.}  
30.  
31.  
32.--[[  
33.  
34.for k=1,#cmdlist do  
35.        print(cmdlist[k].send)  
36.        print(cmdlist[k].plain)  
37.        print(cmdlist[k].dalay)  
38.  
39.end  
40.  
41.--]]  

lua运行结果

	w 0x0000 0x0001
	2
	???
	w 0x0000 0x0002
	2  
	???
	w 0x0000 0x0003
	2 
	???
	w 0x0000 0x0004
	2
	???

#三、C API的使用

lua_State * luaL_newstate(void)

 新建一个lua_State 结构的指针,用以记录栈的状态

luaL_openlibs(lua_State * L)

打开所有的lua标准库

luaL_loadfile(lua_State * L,char* filepath)

加载并运行lua程序文件

##int lua_pcall (lua_State *L, int nargs, int nresults, int msgh);
lua_pcall(L,0,0,0)调用时,检测栈顶是否有存在错误

lua_close

销毁对象

##main函数实现

int main( int argc,char** argv)  
{  
        int error;  
        char buff[256];  
  
        char *filename = argv[1];      
  
        lua_State *L =luaL_newstate();;  
  
        luaL_openlibs(L);  
		//加载运行,检测是否有错误
        if(luaL_loadfile(L,filename) || lua_pcall(L,0,0,0))  
        {      
                luaL_error(L,"loadfile error! %s \n",lua_tostring(L,-1));      
        }
		//遍历函数,下面会写他的实现
        get_table(L ,"cmdlist");  
  
        lua_close(L);  
  
       return 0;  
} 

#四、C中的遍历函数
##1、void get_table(lua_State * L ,char * tabname)

void get_table(lua_State * L ,char * tabname)  
{  
        int it_idx=0;  
        printf("二维表的遍历\n");    

        lua_getglobal(L,tabname);                               //(1)
        it_idx = lua_gettop(L);  

        printf("t_id=%d\n",it_idx);  
        lua_pushnil(L);                                         //(2)

        while (lua_next(L, -2)) //stack -2 == tabname           //(3)
        {  
                printf("============================\n");  
                lua_pushnil(L);                                 //(4)

                while(lua_next(L, -2))                          //(5)
                {  
                        printf("%s\n", lua_tostring(L, -1));  
                        lua_pop(L, 1);                          //(6) 
                }  
                lua_pop(L, 1);                                  //(7) 
        }  

        lua_pop(L,1);                                           //(8) 
}

##2、 虚拟栈
lua和C之间的数据交换是通过一个虚拟栈实现的,这个栈严格遵守先进后出的原则;可以用 1 ~ N 从栈底向上索引,也可以用 -1 ~ -N 从栈顶向下索引,一般后者更加常用,C通过压栈一个元素,或者弹栈一个元素,获取自己想要的数据。

##3.遍历中使用到的函数
###lua_getglobal
手册中的描述

lua_getglobal int lua_getglobal (lua_State *L, const char *name);
Pushes onto the stack the value of the global name. Returns the type
of that value.

向栈中压入一个name对应的lua中的元素,返回这个元素的类型

###lua_pushnil
手册中的描述

lua_pushnil
void lua_pushnil (lua_State *L);
Pushes a nil value onto the stack.

向栈中压入一个空值

###lua_next
手册中的描述

lua_next

int lua_next (lua_State *L, int index); Pops a key from the stack, and
pushes a key–value pair from the table at the given index (the “next”
pair after the given key). If there are no more elements in the table,
then lua_next returns 0 (and pushes nothing).

A typical traversal looks like this:

 /* table is in the stack at index 't' */
 lua_pushnil(L);  /* first key */
 while (lua_next(L, t) != 0) {
   /* uses 'key' (at index -2) and 'value' (at index -1) */
   printf("%s - %s\n",
          lua_typename(L, lua_type(L, -2)),
          lua_typename(L, lua_type(L, -1)));
   /* removes 'value'; keeps 'key' for next iteration */
   lua_pop(L, 1);
 } While traversing a table, do not call lua_tolstring directly on a key, unless you know that the key is actually a string. Recall that

lua_tolstring may change the value at the given index; this confuses
the next call to lua_next.

See function next for the caveats of modifying the table during its
traversal.

这个函数以参数index指向的栈中的元素为对象,以栈顶元素的下一个为索引,先将栈顶弹出,再讲index指向的元素的key和value压入栈中。

简单来说就是,弹栈,压栈压栈。

###lua_pop

void lua_pop (lua_State *L, int n);
Pops n elements from the stack.

从栈中弹出n个元素

##4.执行过程

根据注释(1)(2)(3)(4)(5)(6)(7)…

  • (1):表名压栈

     			    顶
     		栈: 表名
    
  • (2):压入一个空元素,等next函数检测到这个空后,会自动的将表的第一个元素加载到栈中

     			顶(-1)    (-2)
     		栈: 空(nil),表名
    
  • (3): 以栈中-2处的元素为表名,将空弹出,获取表名的key和value,依次压栈

     			    顶
     		栈: value,key,表名
    

注意 :由于是二维表,此时的value是一个表
结构如下

		[1]=
		{  
		        send="w 0x0000 0x0001",  
		        plain="???",  
		        dalay=2 --[[ms]]  
		}, 
  • (4):作用同2

                  顶
     		栈: 空(nil),value,key,表名
    
  • (5)以栈中-2处的元素为表名,将空弹出,获取表名的key和value,依次压栈
    注意:此时的-2处的元素,是表的一维的值,也就是

 [1]=
		{  
		        send="w 0x0000 0x0001",  
		        plain="???",  
		        dalay=2 --[[ms]]  
		}, 

所以这个执行完成后的栈的样子是

	             顶
			栈:w 0x0000 0x0001 ,send,value,key,表名
  • (6)从栈顶弹出一个元素;

                  顶
     		栈:send,value,key,表名
    

下一次的next会弹出send,压入send之后的key和value,当没有可用的key,栈中为

	             顶
			栈:value,key,表名
  • (7)同上,一个内层循环结束,这句执行完成后的栈是:

                顶
     		栈:key,表名
    

    准备取key的下一个值,如果没有下一个了

     	           顶
     		栈:表名
    
  • (8)将表名弹出,此时的栈为空

#五、运行结果

 ./test config.lua 

二维表的遍历 
t_id=1 
============================ 
w 0x0000 0x0001 
2 
??? 
============================ 
w 0x0000 0x0002 
2 
??? 
============================ 
w 0x0000 0x0003 
2 
??? 
============================ 
w 0x0000 0x0004 
2 
??? 

#六、网上遇到的错误例子

#七、结束语
刚刚开始接触lua,如果有哪里说的不对或者不完善,欢迎指出。网上的错误例子是促使我写这个笔记的原因,太坑了,我不确定是不是别人用错了或者是版本不一致导致的,我使用的版本是v5.3.4。

ps:例子改天再加主要是lua_next函数的使用

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值