C中的lua二维表遍历

来源:互联网 发布:冰川网络远征ol珍宝阁 编辑:程序博客网 时间:2024/05/22 06:28

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函数的使用

原创粉丝点击