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。

第一次使用markdown,感觉不错。

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

你可能感兴趣的:(lua,lua,C,二维表,c语言)