zoukankan      html  css  js  c++  java
  • lua52 C API测试代码

    //这是一篇lua与C++交互的情景测试
    #include <lua.hpp>
    #include <lauxlib.h>
    #include <lualib.h>
    #include <string.h>
    #include <limits.h>
    
    #pragma region not_importent_
    static void stackDump (lua_State *L)
    {
        int i;
        int top = lua_gettop(L);
        for(i=1;i<=top;i++){
            /*repeatforeachlevel*/
            int t = lua_type(L, i);
            switch (t) {
            case LUA_TSTRING:
                /* strings */
                printf("`%s'", lua_tostring(L, i));
                break;
            case LUA_TBOOLEAN:
                /* booleans */
                printf(lua_toboolean(L, i) ? "true" : "false");
                break;
            case LUA_TNUMBER:
                /* numbers */
                printf("%g", lua_tonumber(L, i));
                break;
            default:
                /* other values */
                printf("%s", lua_typename(L, t));
                break;
            }
            printf(" ");
            /* put a separator */
        }
        printf("
    ");
        /* end the listing */
    }
    
    void error (lua_State *L, const char *fmt, const char *str) {
        printf(fmt, str);
    }
    //待Lua调用的C注册函数。
    static int add2(lua_State* L)
    {
        //检查栈中的参数是否合法,1表示Lua调用时的第一个参数(从左到右),依此类推。
        //如果Lua代码在调用时传递的参数不为number,该函数将报错并终止程序的执行。
        double op1 = luaL_checknumber(L,1);
        double op2 = luaL_checknumber(L,2);
        //将函数的结果压入栈中。如果有多个返回值,可以在这里多次压入栈中。
        lua_pushnumber(L,op1 + op2);
        //返回值用于提示该C函数的返回值数量,即压入栈中的返回值数量。
        return 1;
    }
    static int sub2(lua_State* L)
    {
        double op1 = luaL_checknumber(L,1);
        double op2 = luaL_checknumber(L,2);
        lua_pushnumber(L,op1 - op2);
        return 1;
    }
    #pragma endregion
    
    //////////////////////////////////////////////////////////////////////////
    void test_c_call_lua_fun_noParam()
    {
        const char* buff = "print("hello")";
        int err;
    
        //init
        lua_State* L = luaL_newstate();
        luaL_openlibs(L);
    
        //load buff
        err = luaL_loadbuffer(L,buff,strlen(buff),"line") ;
        err += lua_pcall(L,0,0,0);
        int s = lua_gettop(L);
        if(err){
            fprintf(stderr,"%s",lua_tostring(L,-1));
            lua_pop(L,1);
        }
    
        //close
        lua_close(L);
    
    }
    //////////////////////////////////////////////////////////////////////////
    void test_c_call_lua_fun_withParam()
    {
        lua_State *L = luaL_newstate();
        luaL_openlibs(L);
        if (luaL_loadfile(L, "luafile2.lua") || lua_pcall(L, 0, 0, 0))
        {
                error(L, "cannot run configuration file: %s",lua_tostring(L, -1));
                return;
        }
        lua_getglobal(L, "do_lua_kk");
        lua_getglobal(L, "a");
        lua_getglobal(L, "do_lua_error");
        lua_getglobal(L, "b");
        lua_getglobal(L, "do_c_one");
        lua_getglobal(L, "do_c");
        lua_getglobal(L, "width");
        lua_getglobal(L, "height");
        // lua_getglobal(L, "do_c_two");
        stackDump(L); //打印结果:function `lua_str_a' function `lua_str_b' function function 999 300
        int k = 100;
    
        k = lua_pcall(L, 2, 1, 1);
        stackDump(L); //打印结果:function `lua_str_a' function `lua_str_b' function 8888 
        /*lua 执行栈上最上面的函数,使用栈上2个参数,向栈压入3个返回值
        使用栈上第1位置的函数do_lua_kk作为错误处理回调函数,输出:
        -------->do_c
        999--add--300-->--2222
        */
        k = lua_pcall(L, 1, 0, 0);
        stackDump(L); 
    
        lua_close(L);
    }
    //////////////////////////////////////////////////////////////////////////
    void test_c_call_lua_fun_withParam2() 
    {
        lua_State* L = luaL_newstate();
    
        //luaL_dostring 等同于luaL_loadstring() || lua_pcall()
        //注意:在能够调用Lua函数之前必须执行Lua脚本,否则在后面实际调用Lua函数时会报错,
        //错误信息为:"attempt to call a nil value."
        const char* lua_function_code = "function add(x,y) return x + y end";
        if (luaL_dostring(L,lua_function_code)) {
            printf("Failed to run lua code.
    ");
            return;
        }
        double x = 1.0, y = 2.3;
        lua_getglobal(L,"add");
        lua_pushnumber(L,x);
        lua_pushnumber(L,y);
        //下面的第二个参数表示带调用的lua函数存在两个参数。
        //第三个参数表示即使带调用的函数存在多个返回值,那么也只有一个在执行后会被压入栈中。
        //lua_pcall调用后,虚拟栈中的函数参数和函数名均被弹出。
        if (lua_pcall(L,2,1,0)) {
            printf("error is %s.
    ",lua_tostring(L,-1));
            return;
        }
        //此时结果已经被压入栈中。
        if (!lua_isnumber(L,-1)) {
            printf("function 'add' must return a number.
    ");
            return;
        }
        double ret = lua_tonumber(L,-1);
        lua_pop(L,-1); //弹出返回值。
        printf("The result of call function is %f.
    ",ret);
        lua_close(L);
    
    }
    //////////////////////////////////////////////////////////////////////////
    void test_c_use_lua_variant()
    {
        const char* luascript = "width=111 ; height=222";
        lua_State* L = luaL_newstate();
        int w,h;
        //luaL_loadfile的作用是编译lua文件为一个chunk
        //把这个chunk当作一个匿名函数压在栈上
        //lua_pcall的作用是执行这个匿名函数,然后才能取得栈上的值
        if(luaL_loadstring(L,luascript) || lua_pcall(L,0,0,0)){
            printf("Error msg is %s.
    ",lua_tostring(L,-1));
            return;
        }
        lua_getglobal(L,"width"); //调用次函数,则把全局变量压栈
        lua_getglobal(L,"height");//这里压栈次序决定了后面取值的索引
        if(!lua_isnumber(L,-2)){
            printf("width must be number
    ");
            return;
        }
        if(!lua_isnumber(L,-1)){
            printf("height must be number
    ");
            return ;
        }
        w = lua_tointeger(L,-2);
        h = lua_tointeger(L,-1);
    
        printf("width = %d height = %d
    ",w,h);
        lua_close(L);
    }
    //////////////////////////////////////////////////////////////////////////
    void test_c_use_lua_table()
    {
        lua_State* L = luaL_newstate();
        if (luaL_loadstring(L,"background = { r = 0.30, g = 0.10, b = 0 }") 
            || lua_pcall(L,0,0,0)) {
                printf("Error Msg is %s.
    ",lua_tostring(L,-1));
                return;
        }
        lua_getglobal(L,"background");
        if (!lua_istable(L,-1)) {
            printf("'background' is not a table.
    " );
            return;
        }
        //下面取栈上的table内容
        lua_getfield(L,-1,"r");
        if (!lua_isnumber(L,-1)) {
            printf("Invalid component in background color.
    ");
            return;
        }
        int r = (int)(lua_tonumber(L,-1) * 255);
        lua_pop(L,1);//出栈
    
        lua_getfield(L,-1,"g");
        if (!lua_isnumber(L,-1)) {
            printf("Invalid component in background color.
    ");
            return;
        }
        int g = (int)(lua_tonumber(L,-1) * 255);
        lua_pop(L,1);
    
        lua_pushnumber(L,0.4);//入栈,栈顶位置-1的值是0.4
        lua_setfield(L,-2,"b");//设置background["b"]=0.4,注意-2这个位置表示table的位置!!
        lua_getfield(L,-1,"b");//取table值
        stackDump(L);
        if (!lua_isnumber(L,-1)) {
            printf("Invalid component in background color.
    ");
            return;
        }
        int b = (int)(lua_tonumber(L,-1) * 255);
        printf("r = %d, g = %d, b = %d
    ",r,g,b);
        lua_pop(L,1);
        stackDump(L);
        lua_pop(L,1); //栈被清空了
    
        lua_close(L);
    }
    //////////////////////////////////////////////////////////////////////////
    void test_c_new_lua_table()
    {
        lua_State* L = luaL_newstate();
        lua_newtable(L);//Lua会生成一个新的table对象并将其压入栈中。
        lua_pushnumber(L,0.3);
        stackDump(L);//table 0.3
        lua_setfield(L,-2,"r");//设置table["r"]=0.3完了把0.3弹出
        stackDump(L);//table
    
        lua_pushnumber(L,0.1);
        lua_setfield(L,-2,"g");
    
        lua_pushnumber(L,0.4);
        lua_setfield(L,-2,"b");
    
        stackDump(L);//table
        lua_setglobal(L,"background");//栈顶元素出栈
        stackDump(L);//nil
        //调用该宏后,Lua会将当前栈顶的值赋值给第二个参数指定的全局变量名。
        //该宏在执行成功后,会将刚刚赋值的值从栈顶弹出。
    
        lua_getglobal(L,"background");//把background压栈
        stackDump(L);//table
        if (!lua_istable(L,-1)) {
            printf("'background' is not a table.
    " );
            return;
        }
        lua_getfield(L,-1,"r");//table["r"]压栈
        stackDump(L);//table 0.3
        if (!lua_isnumber(L,-1)) {
            printf("Invalid component in background color.
    ");
            return;
        }
        int r = (int)(lua_tonumber(L,-1) * 255);
        lua_pop(L,1);//table
    
        lua_getfield(L,-1,"g");//table 0.1
        if (!lua_isnumber(L,-1)) {
            printf("Invalid component in background color.
    ");
            return;
        }
        int g = (int)(lua_tonumber(L,-1) * 255);
        lua_pop(L,1);//table
    
        lua_getfield(L,-1,"b");//table 0.4
        if (!lua_isnumber(L,-1)) {
            printf("Invalid component in background color.
    ");
            return;
        }
        int b = (int)(lua_tonumber(L,-1) * 255);
        printf("r = %d, g = %d, b = %d
    ",r,g,b);
        lua_pop(L,1);//table
        lua_pop(L,1);//nil
    
        lua_close(L);
    }
    //////////////////////////////////////////////////////////////////////////
    void test_lua_call_c_fun()
    {
        const char* testfunc = "print(add2(1.0,2.0)) print(sub2(20.1,19))";
        lua_State* L = luaL_newstate();
        luaL_openlibs(L);
        //将指定的函数注册为Lua的全局函数变量,其中第一个字符串参数为Lua代码在调用C函数时使用的全局函数名
        //,第二个参数为实际C函数的指针。
        lua_register(L, "add2", add2);
        lua_register(L, "sub2", sub2);
        //在注册完所有的C函数之后,即可在Lua的代码块中使用这些已经注册的C函数了。
        if (luaL_dostring(L,testfunc))
            printf("Failed to invoke.
    ");
        lua_close(L);
    }
    //////////////////////////////////////////////////////////////////////////
    //lua文件里的print被C调用时,是可以打印到终端的!!!
    void test_lua_call_c_dll_fun()
    {
        lua_State* L = luaL_newstate();
        luaL_openlibs(L);
        if(luaL_dofile(L,"lua_call_c.lua"))
            printf("load lua_call_c.lua failed
    ");;
        lua_close(L);
    }
    
    
    #define BITS_PER_WORD (CHAR_BIT * sizeof(int))
    #define I_WORD(i)     ((unsigned int)(i))/BITS_PER_WORD
    #define I_BIT(i)      (1 << ((unsigned int)(i)%BITS_PER_WORD))
    
    typedef struct NumArray {
        int size;
        unsigned int values[1];
    } NumArray;
    
    extern "C" int newArray(lua_State* L)
    {
        //1. 检查第一个参数是否为整型。以及该参数的值是否大于等于1.
        int n = luaL_checkint(L,1);
        luaL_argcheck(L, n >= 1, 1, "invalid size.");
        size_t nbytes = sizeof(NumArray) + I_WORD(n - 1) * sizeof(int);
        //2. 参数表示Lua为userdata分配的字节数。同时将分配后的userdata对象压入栈中。
        NumArray* a = (NumArray*)lua_newuserdata(L,nbytes);
        a->size = n;
        for (int i = 0; i < I_WORD(n - 1); ++i)
            a->values[i] = 0;
        //获取注册表变量myarray,该key的值为metatable。
        luaL_getmetatable(L,"myarray");
        //将userdata的元表设置为和myarray关联的table。同时将栈顶元素弹出。
        lua_setmetatable(L,-2);
        return 1;
    }
    
    extern "C" int setArray(lua_State* L)
    {
        //1. Lua传给该函数的第一个参数必须是userdata,该对象的元表也必须是注册表中和myarray关联的table。
        //否则该函数报错并终止程序。
        NumArray* a = (NumArray*)luaL_checkudata(L,1,"myarray");
        int index = luaL_checkint(L,2) - 1;
        //2. 由于任何类型的数据都可以成为布尔值,因此这里使用any只是为了确保有3个参数。
        luaL_checkany(L,3);
        luaL_argcheck(L,a != NULL,1,"'array' expected.");
        luaL_argcheck(L,0 <= index && index < a->size,2,"index out of range.");
        if (lua_toboolean(L,3))
            a->values[I_WORD(index)] |= I_BIT(index);
        else
            a->values[I_WORD(index)] &= ~I_BIT(index);
        return 0;
    }
    
    extern "C" int getArray(lua_State* L)
    {
        NumArray* a = (NumArray*)luaL_checkudata(L,1,"myarray");
        int index = luaL_checkint(L,2) - 1;
        luaL_argcheck(L, a != NULL, 1, "'array' expected.");
        luaL_argcheck(L, 0 <= index && index < a->size,2,"index out of range");
        lua_pushboolean(L,a->values[I_WORD(index)] & I_BIT(index));
        return 1;
    }
    
    extern "C" int getSize(lua_State* L)
    {
        NumArray* a = (NumArray*)luaL_checkudata(L,1,"myarray");
        luaL_argcheck(L,a != NULL,1,"'array' expected.");
        lua_pushinteger(L,a->size);
        return 1;
    }
    
    extern "C" int array2string(lua_State* L)
    {
        NumArray* a = (NumArray*)luaL_checkudata(L,1,"myarray");
        lua_pushfstring(L,"array(%d)",a->size);
        return 1;
    }
    
    static luaL_Reg arraylib_f [] = { 
        {"new", newArray},
        {NULL, NULL} 
    }; 
    
    static luaL_Reg arraylib_m [] = {
        {"set", setArray},
        {"get", getArray},
        {"size", getSize},
        {"__tostring", array2string}, //print(a)时Lua会调用该元方法。
        {NULL, NULL} 
    };
    
        int luaopen_testuserdata(lua_State* L)
    {
        //1. 创建元表,并将该元表指定给newArray函数新创建的userdata。在Lua中userdata也是以table的身份表现的。
        //这样在调用对象函数时,可以通过验证其metatable的名称来确定参数userdata是否合法。
        luaL_newmetatable(L,"myarray");
        lua_pushvalue(L,-1);
        //2. 为了实现面对对象的调用方式,需要将元表的__index字段指向自身,同时再将arraylib_m数组中的函数注册到
        //元表中,之后基于这些注册函数的调用就可以以面向对象的形式调用了。
        //lua_setfield在执行后会将栈顶的table弹出。
        lua_setfield(L,-2,"__index");
        //将这些成员函数注册给元表,以保证Lua在寻找方法时可以定位。NULL参数表示将用栈顶的table代替第二个参数。
        luaL_newlib(L,arraylib_m);
        //这里只注册的工厂方法。
        luaL_newlib(L,arraylib_f);
        return 1;
    }
    int main()
    {
        test_c_call_lua_fun_noParam();
        test_c_call_lua_fun_withParam();
        test_c_call_lua_fun_withParam2();
        test_c_use_lua_variant();
        test_c_use_lua_table();
        test_c_new_lua_table();
        test_lua_call_c_fun();
        test_lua_call_c_dll_fun();
        getchar();
        return 0;
    }
  • 相关阅读:
    svn 更新
    首尾渐变
    sublime常用快捷键
    【CSS3】transition过渡和animation动画
    JS实现奇偶数的判断
    style、currentStyle、getComputedStyle区别介绍
    JavaScript中判断对象类型的种种方法
    CSS3 animation动画,循环间的延时执行时间
    EMCA创建em资料库时报错
    OS Kernel Parameter.semopm
  • 原文地址:https://www.cnblogs.com/jwk000/p/3572250.html
Copyright © 2011-2022 走看看