• Lua C Api


    Lua 5.1 参考手册

    C API是一个C代码与Lua进行交互的函数集。它有以下部分组成:读写Lua全局变量的函数,调用Lua函数的函数,运行Lua代码片断的函数,注册C函数然后可以在Lua中被调用的函数,等等。

      在C和Lua之间通信关键内容在于一个虚拟的栈。几乎所有的API调用都是对栈上的值进行操作,所有C与Lua之间的数据交换也都通过这个栈来完成。

      头文件lua.h定义了Lua提供的基础函数。其中包括创建一个新的Lua环境的函数(如lua_open),调用Lua函数(如lua_pcall)的函数,读取/写入Lua环境的全局变量的函数,注册可以被Lua代码调用的新函数的函数,等等。所有在lua.h中被定义的都有一个lua_前缀。头文件lauxlib.h定义了辅助库(auxlib)提供的函数。同样,所有在其中定义的函数等都以luaL_打头(例如,luaL_loadbuffer)。辅助库利用lua.h中提供的基础函数提供了更高层次上的抽象;所有Lua标准库都使用了auxlib。

      Lua库没有定义任何全局变量。它所有的状态保存在动态结构lua_State中,而且指向这个结构的指针作为所有Lua函数的一个参数。

    /*
    ** basic stack manipulation
    */
    LUA_API int (lua_absindex) (lua_State *L, int idx);
    LUA_API int (lua_gettop) (lua_State *L);
    LUA_API void (lua_settop) (lua_State *L, int idx);
    LUA_API void (lua_pushvalue) (lua_State *L, int idx); --函数lua_pushvalue压入堆栈上指定索引的一个拷贝到栈顶
    LUA_API void (lua_rotate) (lua_State *L, int idx, int n);
    LUA_API void (lua_copy) (lua_State *L, int fromidx, int toidx);
    LUA_API int (lua_checkstack) (lua_State *L, int n);
    
    LUA_API void (lua_xmove) (lua_State *from, lua_State *to, int n);
    
    
    /*
    ** access functions (stack -> C)
    */
    
    LUA_API int (lua_isnumber) (lua_State *L, int idx);
    LUA_API int (lua_isstring) (lua_State *L, int idx);
    LUA_API int (lua_iscfunction) (lua_State *L, int idx);
    LUA_API int (lua_isinteger) (lua_State *L, int idx);
    LUA_API int (lua_isuserdata) (lua_State *L, int idx);
    LUA_API int (lua_type) (lua_State *L, int idx);
    LUA_API const char *(lua_typename) (lua_State *L, int tp);
    
    LUA_API lua_Number (lua_tonumberx) (lua_State *L, int idx, int *isnum);
    LUA_API lua_Integer (lua_tointegerx) (lua_State *L, int idx, int *isnum);
    LUA_API int (lua_toboolean) (lua_State *L, int idx);
    LUA_API const char *(lua_tolstring) (lua_State *L, int idx, size_t *len);
    LUA_API size_t (lua_rawlen) (lua_State *L, int idx);
    LUA_API lua_CFunction (lua_tocfunction) (lua_State *L, int idx);
    LUA_API void    *(lua_touserdata) (lua_State *L, int idx);
    LUA_API lua_State *(lua_tothread) (lua_State *L, int idx);
    LUA_API const void *(lua_topointer) (lua_State *L, int idx);
    --lua_isnumber和lua_isstring函数不检查这个值是否是指定的类型,而是看它是否能被转换成指定的那种类型。例如,任何数字类型都满足lua_isstring。
    /*
    ** push functions (C -> stack)
    */
    LUA_API void (lua_pushnil) (lua_State *L); 
    LUA_API void (lua_pushnumber) (lua_State *L, lua_Number n);
    LUA_API void (lua_pushinteger) (lua_State *L, lua_Integer n);
    LUA_API const char *(lua_pushlstring) (lua_State *L, const char *s, size_t len);
    LUA_API const char *(lua_pushstring) (lua_State *L, const char *s);
    LUA_API const char *(lua_pushvfstring) (lua_State *L, const char *fmt,
    va_list argp);
    LUA_API const char *(lua_pushfstring) (lua_State *L, const char *fmt, ...);
    LUA_API void (lua_pushcclosure) (lua_State *L, lua_CFunction fn, int n);
    LUA_API void (lua_pushboolean) (lua_State *L, int b);
    LUA_API void (lua_pushlightuserdata) (lua_State *L, void *p);
    LUA_API int (lua_pushthread) (lua_State *L);
    --Lua中的字符串不是以零为结束符的;它们依赖于一个明确的长度,因此可以包含任意的二进制数据。
    --将字符串压入串的正式函数是lua_pushlstring,它要求一个明确的长度作为参数。对于以零结束的字符串,你可以用lua_pushstring(它用strlen来计算字符串长度)
    /* ** get functions (Lua -> stack) */ LUA_API int (lua_getglobal) (lua_State *L, const char *name); LUA_API int (lua_gettable) (lua_State *L, int idx);--接受table在栈中的位置为参数,将对应key值出栈,返回与key对应的value key为栈顶元素 LUA_API int (lua_getfield) (lua_State *L, int idx, const char *k); LUA_API int (lua_geti) (lua_State *L, int idx, lua_Integer n); LUA_API int (lua_rawget) (lua_State *L, int idx); LUA_API int (lua_rawgeti) (lua_State *L, int idx, lua_Integer n); LUA_API int (lua_rawgetp) (lua_State *L, int idx, const void *p); LUA_API void (lua_createtable) (lua_State *L, int narr, int nrec); LUA_API void *(lua_newuserdata) (lua_State *L, size_t sz); LUA_API int (lua_getmetatable) (lua_State *L, int objindex); LUA_API int (lua_getuservalue) (lua_State *L, int idx); /* ** set functions (stack -> Lua) */ LUA_API void (lua_setglobal) (lua_State *L, const char *name); LUA_API void (lua_settable) (lua_State *L, int idx); LUA_API void (lua_setfield) (lua_State *L, int idx, const char *k); LUA_API void (lua_seti) (lua_State *L, int idx, lua_Integer n); LUA_API void (lua_rawset) (lua_State *L, int idx); LUA_API void (lua_rawseti) (lua_State *L, int idx, lua_Integer n); LUA_API void (lua_rawsetp) (lua_State *L, int idx, const void *p); LUA_API int (lua_setmetatable) (lua_State *L, int objindex); LUA_API void (lua_setuservalue) (lua_State *L, int idx);

    #define lua_insert(L,idx) lua_rotate(L, (idx), 1) --移动栈顶元素到指定索引的位置,并将这个索引位置上面的元素全部上移至栈顶被移动留下的空隔

    #define lua_remove(L,idx) (lua_rotate(L, (idx), -1), lua_pop(L, 1))--移除指定索引位置的元素,并将其上面所有的元素下移来填补这个位置的空白

    #define lua_replace(L,idx) (lua_copy(L, -1, (idx)), lua_pop(L, 1))--从栈顶弹出元素值并将其设置到指定索引位置,没有任何移动操作

     

    原文: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
    ",
                  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 
    ", 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); /*栈平衡*/
    复制代码
  • 相关阅读:
    SyncNavigator V8.6.2数据库同步工具安装与卸载
    数据库同步软件|SyncNavigator数据库同步软件 V8.6.2官网下载地址
    sql server两个数据库同步
    怎么实现数据库异地同步备份
    两台服务器数据库同步
    如何实现数据实时同步
    数据库同步软件|SyncNavigator数据库同步软件 V8.6.2
    syncnavigator使用说明
    go 编译
    Go语言实现FastDFS分布式存储系统WebAPI网关
  • 原文地址:https://www.cnblogs.com/slysky/p/7373365.html
Copyright © 2020-2023  润新知