• Lua 和 C 交互中虚拟栈的操作


    Lua 和 C 交互中虚拟栈的操作

    /* int lua_pcall(lua_State *L, int nargs, int nresults, int msgh)
     * 以保护模式调用具有"nargs"个参数,"nresults"个返回值得函数。函数在第一个参数的前一个位置。
     * 保护模式指的是当调用出错时不会报错,而是返回一个错误码同时将错误信息入栈。
     * 当调用成功时,函数返回0。将函数名以及参数出栈,之后将函数的返回值入栈。
     * 无论函数返回多少个返回值,Lua会调整为你需要的数量,忽略多余的或者将不够的补为"nil"。
     * 当调用出错时,函数返回非0值。将函数名以及参数出栈,
     * 以错误信息作为参数,执行虚拟栈中索引"msgh"处的出错处理函数,
     * 将出错处理函数的返回值作为"lua_pcall"的返回值入栈。
     * "msgh"为0代表没有错误处理函数,错误处理函数必须要在被调用函数和其参数入栈之前入栈。
     * 典型的用法中,错误处理函数被用来给错误消息加上更多的调试信息,比如栈跟踪信息。
     * 这些信息在"lua_pcall"返回后,由于栈已经展开,所以收集不到了。
     * lua_pcall 函数会返回下列常数(定义在"lua.h"内)中的一个:
       LUA_OK (0): 成功。
       LUA_ERRRUN: 运行时错误(一般错误)。
       LUA_ERRMEM: 内存分配错误(此种情况,Lua不会调用错误处理函数)。
       LUA_ERRERR: 在运行错误处理函数时发生的错误(此种情况,Lua不会再次调用错误处理函数)。
       LUA_ERRGCMM: 在运行"__gc"元方法时发生的错误(这个错误和被调用的函数无关。)。
     */
    #include <iostream>
    #include <lua.hpp>
    
    /* // lua.hpp 中的内容
    // lua 是以ANSI C编写的, 所以在C++中使用必须加上 extern "C" { } , 显示的告诉编译器以C的方式编译代码
    extern "C" {
    #include "lua.h"
    #include "lualib.h"
    #include "lauxlib.h"
    }
    */
    
    /*
     * Lua中的字符串可以不以''作为结束符。这样,字符串中可以包含任意的二进制(甚至是''),字符串的长度由明确的长度指定
     * 在lua_pushlstring()、lua_pushliteral()以及lua_pushstring()中,Lua不保存字符串(变量)指针。因此当这些函数返回时,你就可以修改你的字符串了
     * 遍历一个”table”时,不要将lua_tolstring()作用在”key”上,这样会导致lua_next()无法正常运行
     *
     * 对于入栈是否有栈空间的情况,你需要自己判断,别忘了现在你是一个C程序员。当Lua启动或者任何Lua调用C的时候,虚拟栈中至少有20个空间(在”lua.h”中LUA_MINSTACK定义),这对于一般情况下够用了,所以一般不用考虑。但有时候确实需要更多的栈空间(比如调用一个不定参数的函数),此时你需要使用lua_checkstack检查栈空间的情况
     *
     * int lua_checkstack(lua_State *L, int sz)
     * 确保堆栈上至少有"n"个额外空位。如果不能把堆栈扩展到相应的尺寸,函数返回"false"。
     * 失败的原因包括将把栈扩展到比固定最大尺寸还大(至少是几千个元素)或分配内存失败。
     * 这个函数永远不会缩小堆栈,如果堆栈已经比需要的大了,那么就保持原样。
     *
     * 在平常的编码中,对于执行失败时会返回0的lua_to*()类别的函数,我们最好先使用lua_is*()类别的函数判断参数的类型,之后再使用lua_to*()类别的函数对参数进行转换;而对于执行失败时会返回NULL的lua_to*()类别的函数,我们可以直接使用lua_to*()类别的函数直接对参数进行转换,判断函数的返回值非NULL与否,就能判断转换是否成功
     *
     * lua_pop()就是通过lua_settop()实现的(在”lua.h”中定义)
     * #define lua_pop(L,n) lua_settop(L, -(n)-1)
     *
     * 以下操作对于虚拟栈没有任何影响, 栈中元素个数还是一样多
     * lua_settop(L, -1);     // set top to its current value
     * lua_insert(L, -1);    // move top element to the top
     * lua_replace(L, -1);    // replace top element by the top element
     *
     */
    
    static void stackDump(lua_State * L)
    {
        int i = 0;
        int top = lua_gettop(L); // 获取栈中元素个数
        std::cout << "lua stack value count: " << top << std::endl;
        for (i = 1; i <= top; ++i) // 遍历栈中每一个元素 // 栈底的序号为1, 依次递增. 栈顶的序号始终为-1
        {
            int t = lua_type(L, i); // 获取元素的类型
            switch (t)
            {
            case LUA_TSTRING: // strings
                std::cout << lua_tostring(L, i);
                break;
    
            case LUA_TBOOLEAN: // bool
                std::cout << (lua_toboolean(L, i) != 0 ? "true" : "false");
                break;
    
            case LUA_TNUMBER: // number
                std::cout << lua_tonumber(L, i);
                break;
    
            default: // other values
                std::cout << lua_typename(L, t); // 将宏定义的类型码转换为类型名称
                break;
            }
            std::cout << " ";
        }
        std::cout << std::endl;
    }
    
    int main()
    {
        lua_State * L = luaL_newstate(); // 创建Lua虚拟机
        luaL_openlibs(L); // 打开Lua状态机"L"中的所有Lua标准库
    
        // 向虚拟栈中压入值
        lua_pushboolean(L, 1);  // true
        lua_pushnumber(L, 10); // 10
        lua_pushnil(L); // nil
        lua_pushstring(L, "hello"); // "hello"
        stackDump(L); // true  10  nil  'hello'
    
        lua_pushvalue(L, -4); // 将索引-4处的值的副本入栈
        stackDump(L); // true  10  nil  'hello'  true
    
        lua_replace(L, 3); // 将栈顶元素移动到索引3处,并覆盖原先的元素
        stackDump(L); // true  10  true  'hello'
    
        lua_settop(L, 6); // 将栈顶设置为索引6处,多出来的新元素被赋值为"nil"
        stackDump(L); // true  10  true  'hello'  nil  nil
    
        lua_remove(L, -3); // 移除索引-3处的元素,其上所有元素下移
        stackDump(L); // true  10  true  nil  nil
    
        lua_settop(L, -5); // 将栈顶设置为索引-5处
        stackDump(L); // true
    
        lua_close(L); // 关闭Lua状态机
    
        std::cout << "..." << std::endl;
        system("pause");
        return 0;
    }
  • 相关阅读:
    2016.10.09
    Httpie 进行web请求模拟
    Python-集合
    python-字典
    MySQL权限系统
    MySQL8.0安装以及介绍(二进制)
    数据库对象中英文介绍
    Python-字符串
    GIT安装部署
    Cobbler安装部署
  • 原文地址:https://www.cnblogs.com/lsgxeva/p/7750331.html
Copyright © 2020-2023  润新知