Lua笔记

本文介绍了如何使用Lua C API进行C函数的注册,包括luaL_register和批量注册的方式。同时,详细讲解了Lua栈的操作,如压入、查询、转换不同类型的元素,以及对表的操作,如lua_getfield和lua_setfield。此外,还提到了lua_rawgeti和lua_rawseti等不触发元方法的操作。
摘要由CSDN通过智能技术生成

注册c函数

一般我们用 luaL_register,比如lua_register(L, "testfunc", testf); 其中testf就是c函数,这样lua就可以调用了

我们还可以批量注册函数

static luaL_Reg mylibs[] = { 
     {"add", add},
     {"sub", sub},
     {NULL, NULL} 
}; 
luaL_register(L,"mylib",mylibs);
这样在lua里面就可以调用,注意调用的时候要加上名字,比如 mylib.add


栈操作相关函数

 1). 压入元素:lua_push*
    Lua针对每种C类型,都有一个C API函数与之对应,如:

    void lua_pushnumber(lua_State* L, lua_Number n); --浮点数
    void lua_pushlstring(lua_State* L, const char* s, size_t len); --指定长度的内存数据
    void lua_pushstring(lua_State* L, const char* s);  --以零结尾的字符串,其长度可由strlen得出。
    对于字符串数据,Lua不会持有他们的指针,而是调用在API时生成一个内部副本,因此,即使在这些函数返回后立刻释放或修改这些字符串指针,也不会有任何问题。
    在向栈中压入数据时,可以通过调用下面的函数判断是否有足够的栈空间可用,一般而言,Lua会预留20个槽位,对于普通应用来说已经足够了,除非是遇到有很多参数的函数。
    int lua_checkstack(lua_State* L, int extra) --期望得到extra数量的空闲槽位,如果不能扩展并获得,返回false。 
    
    2). 查询元素:int lua_is* (lua_State *L, int index);,比如
    int lua_islightuserdata (lua_State *L, int index);
    int lua_isnumber (lua_State *L, int index);
    int lua_isuserdata (lua_State *L, int index);
    以上函数,成功返回1,否则返回0。需要特别指出的是,对于lua_isnumber而言,不会检查值是否为数字类型,而是检查值是否能转换为数字类型。
    Lua还提供了一个函数lua_type,用于获取元素的类型,函数原型如下:
    int lua_type (lua_State *L, int index);
    该函数的返回值为一组常量值,分别是:LUA_TNIL、LUA_TNUMBER、LUA_TBOOLEAN、LUA_TSTRING、LUA_TTABLE、LUA_TFUNCTION、LUA_TUSERDATA、LUA_TTHREAD和LUA_TLIGHTUSERDATA

    
    3)转换函数,ua_to* (lua_State *L, int index),如:
    int lua_toboolean (lua_State *L, int index);

    查询和转换函数都不会将元素从堆栈里面抛出

   4)其它函数
   lua_getglobal(lua_State* L, char* name) 从lua的全局表里面取出名字为name的值,这个函数其实是一个宏定义,#define lua_getglobal(L,s) lua_getfield(L, LUA_GLOBALSINDEX, (s)),c++先把name压栈,然后lua从栈中抛出这个name,取值压栈,就是说调用之后是name对应的值在栈顶,需要我们通过lua_to*函数取出来

 lua_setglobal则是设置lua中的全局变量值

    int lua_gettop(lua_State* L); --返回栈中元素的个数。
    void lua_settop(lua_State* L, int index); --将栈顶设置为指定的索引值。
    void lua_pushvalue(lua_State* L, int index); --将指定索引的元素副本压入栈。
    void lua_remove(lua_State* L, int index); --删除指定索引上的元素,其上面的元素自动下移。
    void lua_insert(lua_State* L, int index); --将栈顶元素插入到该索引值指向的位置。

    void lua_replace(lua_State* L, int index); --弹出栈顶元素,并将该值设置到指定索引上。

     lua_pop(L,n) 抛出栈顶的n个元素


5)通过堆栈对表的操作

  void lua_getfield(lua_State *L, int idx, const char *k); 第二个参数是table变量在栈中的索引值,最后一个参数是table的键值,该函数执行成功后会将字段值压入栈中。
    void lua_setfield(lua_State *L, int idx, const char *k); 第二个参数是table变量在栈中的索引值,最后一个参数是table的键名称,而字段值是通过上一条命令压入到栈中的,该函数在执行成功后会将刚刚压入的字段值弹出栈


    读取表,先通过lua_getglobal得到表,然后获取表里面的元素比如lua里面有一张表 tbtest = { mem1=5, mem2=7.9}

   lua_getglobal(L,"tbltest"); //这时候tbltest已经放在栈顶了

  lua_getfield(L, -1, "mem1");// 这样就把 mem1的值放入到栈顶了

  int nmem1 = lua_tointeger(L, -1);

  lua_pop(L, 1); //这样tbltest又回到栈顶了

  double dbmem2 = lua_tonumber(L, -1);

  

表的操作

1.  建一个新表

void lua_createtable (lua_State *L, int narr, int nrec)
创建一个新的table, 并把它放在栈顶. narr和nrec分别指定该table的array部分和hash部分的预分配元素数量
无返回值
栈高度+1, 栈顶元素是新table
#define lua_newtable(L) lua_createtable(L, 0, 0) 常用这个
 
2. 取表中的元素
void lua_getfield (lua_State *L, int index, const char *k)
操作:   arr = Stack[index]    // arr肯定是表
        Stack.push( arr[k] )
取表中键为k的元素, 这里的表是由index指向的栈上的一个表
无返回值
栈高度+1, 栈顶元素是(Stack[index])[k]
注意, 该操作将触发 __index 元方法
 
3. 给表中的元素赋值
void lua_setfield (lua_State *L, int index, const char *k)
操作:   arr = Stack[index]
        arr[k] = Stack.top()
        Stack.pop()
给表中键为k的元素赋值value(value就是栈顶元素), 这里的表是由index指向的栈上的一个表
无返回值
栈高度-1, 被弹出的是value
注意, 该操作将触发 __newindex 元方法
 
4. 取表元素 和 表元素赋值
void lua_gettable (lua_State *L, int index)

操作:     ele  = Stack[index]

            key = Stack.top()

            Stack.pop()

            value = ele[key]

            Stack.push(value)

根据index指定取到相应的表; 取栈顶元素为key, 并弹出栈; 获取表中key的值压入栈顶.

无返回值

栈高度不变, 但是发生了一次弹出和压入的操作, 弹出的是key, 压入的是value

注意, 该操作将触发 __index 元方法

 

void lua_settable (lua_State *L, int index)
操作:   ele    = Stack[index]
        value  = Stack.top()
        Stack.pop()
        key    = Stack.top()
        Stack.pop()
        ele[key] = value
根据index指定取到相应的表; 取栈顶元素做value, 弹出之; 再取当前栈顶元素做key, 亦弹出之; 然后将表的键为key的元素赋值为value
无返回值
栈高度-2, 第一次弹出value, 第二次弹出key
注意, 该操作将触发 __newindex 元方法
 
5. 对table的一些操作[不引发原方法]
void lua_rawget (lua_State *L, int index)

和lua_gettable操作一样

但是不触发相应的元方法

  

void lua_rawgeti(lua_State *L, int index, int n)

操作:   ele = Stack[index]

        value = ele[n]

        Stack.push(value)

无返回值

栈+1, 栈顶新增元素就是 value

不触发相应的元方法

  

void lua_rawset (lua_State *L, int index) 

和lua_settable操作一样

 但是不触发相应的原方法

 

void lua_rawseti (lua_State *L, int index, int n) 

操作:   ele = Stack[index]

        value = Stack.top()

        Stack.pop()

        ele[n] = value

无返回值

栈-1, 栈顶将value弹出

不触发相应的元方法

 

 

6. 复制栈上元素并压入栈

void lua_pushvalue (lua_State *L, int index)

操作:   value = Stack[index]       

       Stack.push(value)

无返回值

栈+1 

 

 

7. 创建一个元表

int luaL_newmetatable (lua_State *L, const char *tname)

操作:   1. 在注册表中查找tname, 如果已经注册, 就返回0, 否者继续, 并平栈

        lua_getfield(L, LUA_REGISTRYINDEX, tname)

        if (!lua_isnil(L, -1))

            return 0;

        lua_pop(L, 1);

        2. 创建一个表, 并注册, 返回1

        lua_newtable(L)

        lua_pushvalue(L, -1)

        lua_setfield(L, LUA_REGISTRYINDEX, tname)

        return 1

有返回值
栈+1, 栈顶元素是在注册表中注册过的新表
 
8. 创建C值
void *lua_newuserdata (lua_State *L, size_t size)

该函数分配一块由size指定大小的内存块, 并放在栈顶

返回值是新分配的块的地址

栈+1, 栈顶是userdata

userdata用来在lua中表示c中的值. 一个完整的userdata有自己的元表, 在垃圾回收时, 可以调用它的元表的__gc方法

 

 

9. 注册c函数到lua中, 其实没有这回事, lua中只有c闭包

void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n)

向栈上压一个C闭包

当一个c函数被创建时, 可以绑定几个值在它上面, 从而形成一个闭包.  在任何时刻调用这个c函数时, 都可以访问这几个绑定值. 

绑定的方法: 先一次压入要绑定的n个值到栈上, 然后调用lua_pushcclosure(L, fn, n)这样就形成的一个c闭包

无返回值

栈 –(n - 1) , 一共弹出n个元素(及那些绑定的值), 压入一个cclosure

 

#define lua_pushcfunction(L, f) lua_pushcclosure(L, f, 0)

#define lua_register(L, n, f) (lua_pushcfunction(L, f), lua_setglobal(L, n))

没有返回值

栈不变化

这个是比较常用的, 以n为lua中的key压入一个0个绑定值的cclosure.













评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值