zoukankan      html  css  js  c++  java
  • C++ Lua

    C++ 调用 Lua

    参考链接:https://blog.csdn.net/shun_fzll/article/details/39120965

    https://www.cnblogs.com/hewei2012/p/6393229.html

    https://www.cnblogs.com/chevin/p/5884657.html

    lua堆栈

    简单来说,Lua和C/c++语言通信的主要方法是一个无处不在的虚拟栈。栈的特点是先进后出。,lua堆栈就是一个struct,*堆栈索引的方式可是是正数也可以是负数,区别是:正数索引1永远表示栈底,负数索引-1永远表示栈顶。*

    ​ N |"str"| -1 栈顶

    ​ : :

    ​ 3 |232_| -2

    ​ 2 |_________table | -3

    ​ 1 |__________func| -N 栈底

    需要注意的是:堆栈操作是基于栈顶的,就是说它只会去操作栈顶的值。

    举例

    #include <iostream>
    #include <string.h>
    #include "lua.h"
    
    using namespace std;
    
    void main()
    {
    	//1.创建一个空 table ,并将之压入堆栈。 它等价于 lua_createtable(L, 0, 0) 
    	lua_State *L = luaL_newstate();
    	
    	//2.入栈操作
    	lua_pushstring(L, "I am so cool~"); 
    	lua_pushnumber(L,20);
        
        //		2	|        20        |  -1   栈顶
        //      1   | "I am so cool~ " |  -2   栈底
    	
        //3.取值操作
    	if( lua_isstring(L,1)){            	//判断是否可以转为string
    		cout<<lua_tostring(L,1)<<endl;	//转为string并返回
    	}
    	if( lua_isnumber(L,2)){
    		cout<<lua_tonumber(L,2)<<endl;
    	}
    	 
    	lua_close(L);	//4.关闭state
    	return ;
    }
    

    常用栈操作

    int   lua_gettop (lua_State *L);			//返回栈顶索引(即栈长度)
    void  lua_settop (lua_State *L, int idx);	//用于把堆栈的栈顶索引设置为指定的数值,多出的数据会被删除
    //10 20 30 40 50 *(从栈底到栈顶,“*”标识为栈顶,有:
    //lua_settop(L, -3) --> 10 20 30 *
    //lua_settop(L, 6) --> 10 20 30 nil nil nil *
    
    void  lua_pushvalue (lua_State *L, int idx);//将idx索引上的值的副本压入栈顶
    // 10 20 30 40 50 *(从栈底到栈顶,“*”标识为栈顶)有:
    // lua_pushvalue(L, 3) --> 10 20 30 40 50 30*
    
    void  lua_remove (lua_State *L, int idx);	//移除idx索引上的值
    // 栈的初始状态为10 20 30 40 50 *(从栈底到栈顶,“*”标识为栈顶,有:
    // lua_remove(L, -3) --> 10 20 40 50*
    void  lua_insert (lua_State *L, int idx);	//移动栈顶元素到指定索引的位置,栈中数目没有改变
    void  lua_replace (lua_State *L, int idx);	//弹出栈顶元素,并替换索引idx位置的值
    //栈的初始状态为10 20 30 40 50 *(从栈底到栈顶,“*”标识为栈顶,有:
    //lua_replace(L, 2) --> 10 50 30 40 * //把50替换到索引的位置,同时去掉栈顶元素
    
    void lua_settable (lua_State *L, int index);
    //作一个等价于 t[k] = v 的操作, 这里 t 是一个给定有效索引 index 处的值, v 指栈顶的值, //而 k 是栈顶之下的那个值。
    
    void lua_pushcfunction (lua_State *L, lua_CFunction f);
    //将一个 C 函数压入堆栈。 这个函数接收一个 C 函数指针,并将一个类型为 function 的 Lua 值 //压入堆栈。当这个栈定的值被调用时,将触发对应的 C 函数。
    void lua_getglobal (lua_State *L, const char *name);	把全局的name的值压到栈顶。
    //lua_is***(lua_State *L, int index); 检查变量是不是某个类型,index指示变量的顺序,栈顶为-1。
    lua_to***(lua_State *L, int index); //获取栈中的变量,然后转换为某个指定的类型,并返回。
    //lua_close(); 销毁所有在指定的Lua State上的所有对象,同时释放所有该State使用的动态分配的空间。
    
    

    主要函数汇总

    压入元素到栈里
    void lua_pushnil (lua_State *L);
    void lua_pushboolean (lua_State *L, int bool);
    void lua_pushnumber (lua_State *L, double n);
    void lua_pushlstring (lua_State *L, const char *s, size_t length);
    把指针 s 指向的长度为 len 的字符串压栈。 Lua 对这个字符串做一次内存拷贝(或是复用一个拷贝), 
    因此 s 处的内存在函数返回后,可以释放掉或是重用于其它用途。 字符串内可以保存有零字符。
    void lua_pushstring (lua_State *L, const char *s);
    把指针 s 指向的以零结尾的字符串压栈。 Lua 对这个字符串做一次内存拷贝(或是复用一个拷贝), 因此 s 处的内存在函数返回后,
    可以释放掉或是重用于其它用途。 字符串中不能包含有零字符;第一个碰到的零字符会认为是字符串的结束。
    void lua_pushcfunction (lua_State *L, lua_CFunction fn);
    
    查询栈里的元素
    lua_isnil (lua_State *L, int index);
    lua_isboolean (lua_State *L, int index);
    int lua_isnumber (lua_State *L, int index);
    int lua_isstring (lua_State *L, int index);
    int lua_isfunction (lua_State *L, int index);
    int lua_istable (lua_State *L, int index);
    int lua_isuserdata (lua_State *L, int index);
    lua_islightuserdata (lua_State *L, int index);
    lua_isthread (lua_State *L, int index);
    
    转换栈里的元素
    int lua_toboolean (lua_State *L, int index);
    double lua_tonumber (lua_State *L, int index);
    const char *lua_tostring (lua_State *L, int index);
    const char *lua_tolstring (lua_State *L, int idx, size_t *len);
    size_t lua_strlen (lua_State *L, int index);
    lua_CFunction lua_tocfunction (lua_State *L, int idx);
    void *lua_touserdata (lua_State *L, int idx);
    lua_State *lua_tothread (lua_State *L, int idx);
    
    Lua栈的维护
    int lua_gettop (lua_State *L);	取得栈顶元素的索引,即栈中元素的个数
    void lua_settop (lua_State *L, int index); 设置栈顶索引,即设置栈中元素的个数,如果index<0,则从栈顶往下数,下同
    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); 从栈顶弹出元素值并将其设置到指定索引位置,栈中的数目减一
    int lua_checkstack (lua_State *L, int extra); 确保堆栈上至少有 extra 个空位。如果不能把堆栈扩展到相应的尺寸,函数返回 false 。这个函数永远不会缩小堆栈。
    
    int lua_pop(L,n);	从栈顶弹出n个元素,它是一个lua_settop的包装:#define lua_pop(L,n) lua_settop(L, -(n)-1)
        
    void lua_pushcfunction (lua_State *L, lua_CFunction f);
    将C函数压栈;接收一个C函数的指针参数,然后将一个Lua.function类型的对象压栈。
        
    lua_register (lua_State *L, const char *name, lua_CFunction f);注册C函数为一个全局变量;
        
    lua_rawget
    
    

    table 相关操作

    lua中有一个全局的表,_G,这个表包含了所有的全局变量.Lua的全局表可以想象成一个map哈希表结构,比如Lua有一个变量:

    例如:

    name = “hello world”

    全局表中存放了name和hello world的对应关系, 可以通过name在全局表中找到对应的hello world

    这样的两个变量实际上就会被lua存储到_G表中去.也就是说_G["a"]就是变量a.

    C/C++想要获取Lua中的name字符串的值, 首先把name放到堆栈(栈顶),方便Lua看到; Lua从堆栈(栈顶)获取到name的值, 此时栈顶变为空; Lua去全局表中查找name对应的字符串; 全局表返回对应的字符串hello world; Lua再次把hello world放到堆栈(栈顶); C/C++从堆栈(栈顶)获取name的值.

    lua_createtable 
    原型: void lua_createtable (lua_State *L, int narr, int nrec); 
    描述: 创建一个新的table并将之放在栈顶.narr是该table数组部分的长度,nrec是该table hash部分的长度. 
    当我们确切的知道要放多少元素到table的时候,使用这个函数,lua可以预分配一些内存,提升性能. 
    如果不确定要存放多少元素可以使用 lua_newtable 函数来创建table. 
    
    lua_newtable 
    原型: void lua_newtable (lua_State *L); 
    描述: 创建一个新的table并将之放在栈顶. 等同于lua_createtable(L, 0, 0). 
    
    lua_getfield 
    原型: void lua_getfield (lua_State *L, int index, const char *k); 
    描述: 将t[k]元素push到栈顶. 其中t是index处的table. 
    这个函数可能触发index元方法. 
    
    lua_setfield 
    原型: void lua_setfield (lua_State *L, int index, const char *k); 
    描述: 为table中的key赋值. t[k] = v . 其中t是index处的table , v为栈顶元素. 
    这个函数可能触发newindex元方法. 
    调用完成后弹出栈顶元素(value). 
    
    lua_gettable 
    原型: void lua_gettable (lua_State *L, int index); 
    描述: 将t[k]元素push到栈顶. 其中t是index处的table,k为栈顶元素. 
    这个函数可能触发index元方法. 
    调用完成后弹出栈顶元素(key). 
    
    lua_settable 
    原型: void lua_settable (lua_State *L, int index); 
    描述: 为table中的key赋值. t[k] = v . 其中t是index处的table , v为栈顶元素. k为-2处的元素. 
    这个函数可能触发newindex元方法. 
    调用完成后弹出栈顶两个元素(key , value) 
    
    lua_rawget 
    原型: void lua_rawget (lua_State *L, int index); 
    描述: 与lua_gettable函数类似, 但是不会触发index元方法. 
    index元方法:当你通过键来访问 table 的时候,如果这个键没有值,那么Lua就会寻找该table的metatable(假定有metatable)中的__index 键。如果__index包含一个表格,Lua会在表格中查找相应的键.
    如果__index包含一个函数的话,Lua就会调用那个函数,table和键会作为参数传递给函数。
    
    lua_rawset 
    原型: void lua_rawset (lua_State *L, int index); 
    描述: 与lua_settable函数类似, 但是不会触发newindex元方法. 
    
    lua_rawgeti 
    原型: void lua_rawgeti (lua_State *L, int index, int n); 
    描述: 将t[n]元素push到栈顶.其中t是index处的table. 
    这个函数不会触发index元方法. 
    
    lua_rawseti 
    原型: void lua_rawseti (lua_State *L, int index, int n); 
    描述: 为table中的key赋值. t[n] = v .其中t是index处的table , v为栈顶元素. 
    这个函数不会触发newindex元方法. 
    调用完成后弹出栈顶元素. 
    
    lua_rawgetp 
    原型: void lua_rawgetp (lua_State *L, int index, const void *p); 
    描述: 将t[p]元素push到栈顶.其中t是index处的table. p是一个lightuserdata. 
    这个函数不会触发index元方法. 
    
    lua_rawsetp 
    原型: void lua_rawsetp (lua_State *L, int index, const void *p); 
    描述: 为table中的key赋值. t[p] = v .其中t是index处的table , p是一个lightuserdata , v为栈顶元素. 
    这个函数不会触发newindex元方法. 
    调用完成后弹出栈顶元素. 
    
    lua_getmetatable 
    原型: int lua_getmetatable (lua_State *L, int index); 
    描述: 将index处元素的元表push到栈顶. 如果该元素没有元表, 函数返回0 , 不改变栈. 
    
    lua_setmetatable 
    原型: void lua_setmetatable (lua_State *L, int index); 
    描述: 将栈顶元素设置为index处元素的元表. 
    调用完成后弹出栈顶元素. 
    
    lua_istable 
    原型: int lua_istable (lua_State *L, int index); 
    描述: 判断index处元素是否为一个table , 如果是返回1,否则返回0. 
    
    lua_pushglobaltable 
    原型: void lua_pushglobaltable (lua_State *L); 
    描述: 将lua的全局表放在栈顶. 
    
    luaL_newmetatable 
    原型: int luaL_newmetatable (lua_State *L, const char *tname); 
    描述: 如果注册表中已经有名为tname的key,则返回0. 
    否则创建一个新table作为userdata的元表. 这个元表存储在注册表中,并以tname为key. 返回1. 
    函数完成后将该元表置于栈顶. 
    
    luaL_getmetatable 
    原型: void luaL_getmetatable (lua_State *L, const char *tname); 
    描述: 将注册表中以tname为key的元表push到栈顶. 
    
    luaL_setmetatable 
    原型: void luaL_setmetatable (lua_State *L, const char *tname); 
    描述: 将栈顶元素存储到注册表中, 它的key为tname. 
    
    luaL_getsubtable 
    原型: int luaL_getsubtable (lua_State *L, int idx, const char *fname); 
    描述: 将 t[fname] push到栈顶, 其中t是index处的table , 并且 t[fname] 也为一个table. 
    如果 t[fname] 原本就存在,返回 true ,否则返回false,并且将 t[fname] 新建为一张空表. 
    
    lua_getglobal 
    原型: void lua_getglobal (lua_State *L, const char *name); 
    描述: 将 t[name] 元素push到栈顶, 其中t为全局表. 
    
    lua_setglobal 
    原型: void lua_setglobal (lua_State *L, const char *name); 
    描述: 为table中的key赋值. t[name] = v . 其中t为全局表. v为栈顶元素. 
    调用完成后弹出栈顶元素(v). 
    
    luaL_newlibtable 
    原型: void luaL_newlibtable (lua_State *L, const luaL_Reg l[]); 
    描述: 创建一张空表, lua预先分配足够的内存用来存储我们创建的函数库. 
    稍后我们可以使用 luaL_setfuncs 函数注册我们的函数库. 
    
    luaL_setfuncs 
    原型: void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup); 
    描述: 将所有 luaL_Reg数组中的函数注册到栈顶的table中. 
    当upvalue个数不为0时,所创建的所有函数共享这些upvalue. -2到-(nup+1)的元素为要注册的upvalue. 
    (注意:这些upvalue是c中的upvalue,不是lua中的upvalue,可以在注册的c函数中通过 lua_upvalueindex(n)获取其值.) 
    调用完成后弹出栈顶的所有upvalue. 
    
    luaL_newlib 
    原型: void luaL_newlib (lua_State *L, const luaL_Reg *l); 
    描述: 创建一个新的table , 并将luaL_Reg数组中的函数注册到其中. 
    它是一个宏 (luaL_newlibtable(L,l), luaL_setfuncs(L,l,0)) 
    
    lua_next 
    原型: int lua_next (lua_State *L, int index); 
    描述: 该函数用来遍历一个table. 
    从栈顶弹出一个key , 并且push一个 key-value对(栈顶key的下一个键值对) ,到栈顶. 
    如果table中没有更多的元素, 函数返回0. 
    遍历开始时栈顶为一个nil , 函数取出第一个键值对. 
    
    通常遍历方法为: 
    lua_pushnil(L); // first key 
    while (lua_next(L, t) != 0) { 
    // uses 'key' (at index -2) and 'value' (at index -1) 
    printf("%s - %s
    ", 
    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); 
    } 
    注意: 在遍历table的时候 ,除非明确的知道key为字符串,不要对栈上的key使用 lua_tolstring 函数 , 
    因为这样有可能改变key的类型 , 影响下一次 lua_next调用. 
    
    lua_rawlen 
    原型: size_t lua_rawlen (lua_State *L, int index); 
    描述: 获取index处元素的长度. 
    对于字符串来说,返回字符串长度. 
    对于table来说,返回#操作符的长度. 不受元方法影响. 
    对于userdata来说,返回内存的大小. 
    其他元素返回0. 
    
    lua_len 
    原型: void lua_len (lua_State *L, int index); 
    描述: 获取index处元素#操作符的结果 , 放置在栈顶. 
    */ 
    
    /* 其他概念: 
    1.伪索引: 
    Lua栈的正常索引 从栈顶算,栈顶为-1,向栈低递减. 从栈低算,栈低为1,向栈顶递增. 
    伪索引是一种索引,他不在栈的位置中,通过一个宏来定义伪索引的位置. 
    伪索引被用来访问注册表,或者在lua_CFunction中访问upvalue. 
    

    lua_call函数

    void lua_call (lua_State *L, int nargs, int nresults);
    //L是执行环境,可以理解为当前栈,nargs参数个数,nresults返回值个数。lua_pcall和该函数区别是多一个参数,用于发生错误处理时的代码返回。
    void lua_pcall(lua_State *L,int nargs, int nresults,int nerrfunc);
    //lua_cpcall则又多一个用于传递用户自定义的数据结构的指针
    
    

    lua_call 举例

    function interpreter(in_str)
      return load(in_str)()
    end
    
    extern "C" {
          #include "include/lua.h"
          #include "include/lauxlib.h"
          #include "include/lualib.h"
    }
    #include <iostream>
    
    bool run(lua_State* L, std::string in_data) {
      lua_getglobal(L, "interpreter");
      lua_pushstring(L, in_data.c_str());
      lua_call(L, 1, 1);
      return lua_toboolean(L, -1);
    }
    
    int main(int argc, char* argv[]) {
      lua_State* L = luaL_newstate();  // 初始化
      luaL_openlibs(L);  //
      if (luaL_loadfile(L, argv[1]) || lua_pcall(L, 0, 0, 0)) {
        std::cout << "error: " << lua_tostring(L, -1) << std::endl;
        return 0;
      }
      std::cout << run(L, "return 2 < 3 and 4 > 6") << std::endl;
      return 0;
    }
    
  • 相关阅读:
    Appium Android 元素定位方法 原生+H5
    Eclipse下Python的MySQLdb的安装以及相关问题
    Python模块包中__init__.py文件的作用
    如何调用另一个python文件中的代码
    Python单元测试框架unittest使用方法讲解
    python利用unittest进行测试用例执行的几种方式
    python随机生成手机号码
    eclipse 安装python后pydev不出现
    Appium 如何模拟返回按键
    python分布式进程
  • 原文地址:https://www.cnblogs.com/heimazaifei/p/12435907.html
Copyright © 2011-2022 走看看