lua5.1、luajit 和 c++ 交互Demo

本人测试环境: centos7 openresty

main.cpp

#include <lua.hpp>
#include <iostream>

using namespace std;

int simple_test(lua_State *L) {
    cout << ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>  into simple_test" << endl;
    cout << "当前栈上数量 = " << lua_gettop(L) << endl;

    // 获取lua脚本传过来的参数
    const char *name = lua_tostring(L, -2);
//    size_t len;
//    const char *name = lua_tolstring(L, -2, &len);
    lua_Integer age = lua_tointeger(L, -1);
    lua_pop(L, 2);

    cout << "name:" << name << "  age:" << age << endl;

    // lua脚本调用函数的返回值
    lua_pushinteger(L, 99);

    cout << "当前栈上数量 = " << lua_gettop(L) << endl;

    return 1;
}

int array_test(lua_State *L) {
    cout << ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>  into array_test" << endl;
    cout << "当前栈上数量 = " << lua_gettop(L) << endl;

    luaL_checktype(L, 1, LUA_TTABLE);

    // 方法 1
    {
        // 因为lua_next 的第1步会先从栈顶弹出一个key, 如果没值会出错,所以这里压个nil,让其不出错
        lua_pushnil(L);

        // lua_next(L, 1) =>   1 是 table在栈中的位置
        // 1. 先从栈顶弹出一个key (因为是数组,所以这个key就是序号了)
        // 2. 从栈指定位置的table中取一对 key-value, 先将key入栈,再将value入栈
        // 3. 如果第2步成功则返回非0值, 否则返回0, 且不向栈中压入任何值
        while (lua_next(L, 1) != 0) {
            cout << "key: " << lua_tonumber(L, -2) << "  value: " << lua_tostring(L, -1) << endl;

            // lua_next会把key弹掉, 所以这里只要弹掉value即可恢复栈
            lua_pop(L, 1);
        }
        lua_pop(L, 1);  // 弹出table
    }

    // 方法 2
    {
//        size_t n = lua_objlen(L, -1);
//        for (int i = 1; i <= n; ++i) {
//            // 索引号压栈
//            lua_pushnumber(L, i);
//
//            //  1. 上一步的num出栈(pop number) , 这里 num = i
//            //  2. 通过这个num,获取索引号对应的值table[num]
//            //  3. 把这个值table[num] 压栈 (push table[num] )
//            lua_gettable(L, 1);
//
//            //  获取这个值table[num]
//            cout << lua_tostring(L, -1) << endl;
//
//            // 出栈, 1 是出栈的数量
//            lua_pop(L, 1);
//        }
//        lua_pop(L, 1);  // 弹出table
    }

    cout << "当前栈上数量 = " << lua_gettop(L) << endl;

    return 0;
}

int map_test(lua_State *L) {
    cout << ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>  into map_test" << endl;
    cout << "当前栈上数量 = " << lua_gettop(L) << endl;

    luaL_checktype(L, 1, LUA_TTABLE);

    // 方法 1
    {
        // 因为lua_next 的第1步会先从栈顶弹出一个key, 如果没值会出错,所以这里压个nil,让其不出错
        lua_pushnil(L);

        // lua_next(L, 1) =>   1 是 table在栈中的位置
        // 1. 先从栈顶弹出一个key
        // 2. 从栈指定位置的table中取一对 key-value, 先将key入栈,再将value入栈
        // 3. 如果第2步成功则返回非0值, 否则返回0, 且不向栈中压入任何值
        while (lua_next(L, 1) != 0) {
            cout << "key: " << lua_tostring(L, -2) << "  value: " << lua_tostring(L, -1) << endl;

            // lua_next会把key弹掉, 所以这里只要弹掉value即可恢复栈
            lua_pop(L, 1);
        }
        lua_pop(L, 1); // 弹出table
    }

    // 方法 2 (根据key 获取 value)
//    {
//        lua_getfield(L, 1, "a");        // 获取到 table["a"] 的值, 压入栈顶
//        cout << "a => " << lua_tostring(L, -1) << endl;
//
//        lua_getfield(L, 1, "b");
//        cout << "b => " << lua_tostring(L, -1) << endl;
//
//        lua_getfield(L, 1, "c");
//        cout << "c => " << lua_tostring(L, -1) << endl;
//
//        lua_getfield(L, 1, "d");
//        cout << "d => " << lua_tostring(L, -1) << endl;
//
//        lua_pop(L, 5);  // 全部弹出
//    }

    cout << "当前栈上数量 = " << lua_gettop(L) << endl;

    return 0;
}

int checkType_test(lua_State *L) {
    cout << ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>  into checkType_test" << endl;
    cout << "当前栈上数量 = " << lua_gettop(L) << endl;

    // luaL_checktype , 一旦类型不符合, 代码不会继续执行
    luaL_checktype(L, -1, LUA_TBOOLEAN);
    cout << "第1个参数类型检查通过" << endl;

    // lua_type , 就算类型不符合, 代码也会继续执行
    int nType = lua_type(L, -2);
    if (nType != LUA_TNUMBER) {
        cout << "第2个参数类型不符合" << endl;
//        luaL_argerror(L, -2, "参数类型不符合");
    }

    lua_pop(L, 2);

    cout << "当前栈上数量 = " << lua_gettop(L) << endl;

    return 0;
}

int ret_test(lua_State *L) {
    cout << ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>  into ret_test" << endl;
    cout << "当前栈上数量 = " << lua_gettop(L) << endl;

    lua_pushstring(L, "张三");
    lua_pushnumber(L, 12);

    cout << "当前栈上数量 = " << lua_gettop(L) << endl;

    return 2;
}

int ret_table_test(lua_State *L) {
    cout << ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>  into ret_table_test" << endl;
    cout << "当前栈上数量 = " << lua_gettop(L) << endl;

    // 创建表,压栈
    lua_newtable(L);

    // 一对key  value 入栈
    // 压入key
    lua_pushstring(L, "name");
    // 压入value
    lua_pushstring(L, "张三");

    // 此时,表在栈底
    // 弹出 key  value 设置到表.  此时,表在栈顶了
    lua_settable(L, 1);

    //-------------------------------
    // 一对key  value 入栈
    // 压入key
    lua_pushstring(L, "age");
    // 压入value
    lua_pushinteger(L, 22);

    // 此时,表在栈底
    // 弹出 key  value 设置到表.  此时,表在栈顶了
    lua_settable(L, 1);


    cout << "当前栈上数量 = " << lua_gettop(L) << endl;

    return 1;
}

int getLuaVar_test(lua_State *L) {
    cout << ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>  into getLuaVar_test" << endl;
    cout << "当前栈上数量 = " << lua_gettop(L) << endl;

    lua_getglobal(L, "g_var1");
    lua_Number num = lua_tonumber(L, -1);
    cout << "g_var1 = " << num << endl;
    lua_pop(L, 1);

    cout << "当前栈上数量 = " << lua_gettop(L) << endl;

    return 0;
}

int set2LuaVar_test(lua_State *L) {
    cout << ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>  into set2LuaVar_test" << endl;
    cout << "当前栈上数量 = " << lua_gettop(L) << endl;

    lua_pushstring(L, "赵六");

    // 将栈顶位置设置为全局变量,并出栈
    lua_setglobal(L, "g_name");

    cout << "当前栈上数量 = " << lua_gettop(L) << endl;

    return 0;
}


int getLuaVar_table_test(lua_State *L) {
    cout << ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>  into getLuaVar_table_test" << endl;
    cout << "当前栈上数量 = " << lua_gettop(L) << endl;

    // 一层map
    {
        cout << "----------- 一层map ----------" << endl;

        lua_getglobal(L, "g_t1");
        {
            lua_getfield(L, -1, "name");  // name的值入栈
            const char *name = lua_tostring(L, -1);
            cout << "name = " << name << endl;
            lua_pop(L, 1);  // 弹掉 name

            lua_getfield(L, -1, "age");  // age的值入栈
            lua_Number age = lua_tonumber(L, -1);
            cout << "age = " << age << endl;
            lua_pop(L, 1);  // 弹掉 age
        }
        lua_pop(L, 1);  //  弹掉 g_t1

        cout << "当前栈上数量 = " << lua_gettop(L) << endl;
    }

    // 嵌套的map
    {
        cout << "----------- 嵌套的map ---------" << endl;

        lua_getglobal(L, "g_t2");
        {
            // 因为lua_next 的第1步会先从栈顶弹出一个key, 如果没值会出错,所以这里压个nil,让其不出错
            lua_pushnil(L);

            // lua_next(L, 1) =>   1 是 table在栈中的位置
            // 1. 先从栈顶弹出一个key
            // 2. 从栈指定位置的table中取一对 key-value, 先将key入栈,再将value入栈
            // 3. 如果第2步成功则返回非0值, 否则返回0, 且不向栈中压入任何值
            while (lua_next(L, 1) != 0) {
                lua_Number key = lua_tonumber(L, -2);
                cout << "key: " << key << endl;

                // 取value的值, 这里的value就是子table, 在栈顶
                {
                    lua_getfield(L, -1, "name");  // 子table中name的值入栈
                    cout << "value: " << lua_tostring(L, -1) << endl;
                    lua_pop(L, 1);  // 弹掉 name

                    lua_getfield(L, -1, "age");   // 子table中age的值入栈
                    cout << "age: " << lua_tonumber(L, -1) << endl;
                    lua_pop(L, 1); // 弹掉 age
                }

                // lua_next会把key弹掉, 所以这里只要弹掉value(子table)即可恢复栈
                lua_pop(L, 1);
                cout << "**********" << endl;
            }
        }
        lua_pop(L, 1); // 弹掉 g_t2
        cout << "当前栈上数量 = " << lua_gettop(L) << endl;
    }

    return 0;
}

int setLuaVar_table_test(lua_State *L) {
    cout << ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>  into setLuaVar_table_test" << endl;
    cout << "当前栈上数量 = " << lua_gettop(L) << endl;

    // 创建表,压栈
    lua_newtable(L);

    // 一对key  value 入栈
    // 压入key
    lua_pushstring(L, "name");
    // 压入value
    lua_pushstring(L, "张三");

    // 此时,表在栈底
    // 弹出 key  value 设置到表.  此时,表在栈顶了
    lua_settable(L, 1);

    //-------------------------------
    // 一对key  value 入栈
    // 压入key
    lua_pushstring(L, "age");
    // 压入value
    lua_pushinteger(L, 22);

    // 此时,表在栈底
    // 弹出 key  value 设置到表.  此时,表在栈顶了
    lua_settable(L, 1);

    // 将此表设置为全局变量
    lua_setglobal(L, "g_varTable");

    cout << "当前栈上数量 = " << lua_gettop(L) << endl;

    return 0;
}

void callLuaFunc_simple(lua_State *L) {
    cout << ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>  into callLuaFunc_simple" << endl;
    cout << "当前栈上数量 = " << lua_gettop(L) << endl;

    const string luaFuncName = "luaSimpleFunc";
    lua_getglobal(L, luaFuncName.c_str());  // 获取lua函数
    if (lua_pcall(L, 0, 0, 0) != 0)   // 调用失败
    {
        // 失败会产生错误,这个错误会压栈。 这里把它出栈,以免内存泄露
        cout << "call " << luaFuncName << " failed ! error = " << lua_tostring(L, -1) << endl;
        lua_pop(L, 1);
    }

    cout << "当前栈上数量 = " << lua_gettop(L) << endl;
}

void callLuaFunc_params_ret(lua_State *L) {
    cout << ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>  into callLuaFunc_params_ret" << endl;
    cout << "当前栈上数量 = " << lua_gettop(L) << endl;

    const char* luaErrorFuncName = "fError";
    lua_getglobal(L, luaErrorFuncName);   // 获取lua错误处理函数

    const char* luaFuncName = "luaParamsAndRetFunc";
    lua_getglobal(L, luaFuncName);  // 获取lua函数

    lua_pushstring(L, "张三");   // 参数1
    lua_pushinteger(L, 23);     // 参数2

    lua_newtable(L);               // 参数3
    // 表在栈中的位置
    int tIdx =  lua_gettop(L);
    // 压入key
    lua_pushstring(L, "score");
    // 压入value
    lua_pushnumber(L, 91.5);
    // 弹出 key  value 设置到表.  此时,表在栈顶了
    lua_settable(L, tIdx);

    // 别忘了设置: 参数个数 、 返回值个数 、 错误处理函数在栈的位置
    if (lua_pcall(L, 3, 2, -5) != 0)   // 调用失败
    {
        cout << "call " << luaFuncName << " failed ! error = " << lua_tostring(L, -2) << endl;
        // 失败会产生错误,这个错误会压栈。 这里把它出栈,以免内存泄露
        lua_pop(L, 1);
    } else {
        // 获取返回值1
        cout << "ret1 = " << lua_tostring(L, -2) << endl;

        // 获取返回值2 (table)
        // 这里演示直接获取字段值。 如要全表遍历,参考之前的代码
        lua_getfield(L, -1, "name");
        cout << "name = " << lua_tostring(L, -1) << endl;
        lua_pop(L, 1);
        lua_getfield(L, -1, "age");
        cout << "age = " << lua_tointeger(L, -1) << endl;
        lua_pop(L, 1);

        // 这里把它出栈,以免内存泄露
        lua_pop(L, 2);    //  有2个返回值
    }

    // 弹出错误处理函数,以免内存泄露
    lua_pop(L, 1);

    cout << "当前栈上数量 = " << lua_gettop(L) << endl;
}

int main() {
    cout << " >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> start <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<" << endl;

    // 创建状态机
    lua_State *L = luaL_newstate();

    // 打开基本库
    luaL_openlibs(L);

    // 获取lua传递过来的普通参数测试 (给lua写的函数)
    lua_register(L, "simple_test", simple_test);

    // 获取lua传递过来的array参数测试 (给lua写的函数)
    lua_register(L, "array_test", array_test);

    // 获取lua传递过来的map参数测试 (给lua写的函数)
    lua_register(L, "map_test", map_test);

    // lua传递过来的参数类型检查测试 (给lua写的函数)
    lua_register(L, "checkType_test", checkType_test);

    // lua调用C++函数的返回值测试 (给lua写的函数)
    lua_register(L, "ret_test", ret_test);

    // lua调用C++函数的返回值(table)测试 (给lua写的函数)
    lua_register(L, "ret_table_test", ret_table_test);

    // 给lua传递c++全局变量值 (lua可用的C++全局变量)
    set2LuaVar_test(L);

    // 给lua传递c++全局变量值(table) (lua可用的C++全局变量)
    setLuaVar_table_test(L);

    // -------- 调用脚本前 ---------

    luaL_dofile(L, "test1.lua");

    // -------- 调用脚本后 ---------

    // c++获取lua的全局变量值 (C++可用的lua全局变量)
    getLuaVar_test(L);

    // c++获取lua的全局变量值(table) (C++可用的lua全局变量)
    getLuaVar_table_test(L);

    // c++调用lua函数
    callLuaFunc_simple(L);

    // c++调用lua函数(带参数和返回值)
    callLuaFunc_params_ret(L);

    // 关闭
    lua_close(L);

    cout << " >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> end <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<";

    return 0;
}

test1.lua

---
--- Generated by EmmyLua(https://github.com/EmmyLua)
--- Created by saber.
--- DateTime: 2022/7/6 17:38
---

------------ array_test ---------------
local t1 = { "张三", "李四", "abc", "1234" }
array_test(t1)
-------------- map_test -------------
local t2 = { a = "张三", b = "李四", c = "abc", d = "1234" }
map_test(t2)

--------------- checkType_test ------------
checkType_test("abc", true)

------------- simple_test --------------
local score = simple_test("张三", 12)
print("score = ", score)
score = nil

------------- ret_test --------------
local ret1, ret2 = ret_test()
print("ret1 = ", ret1, "  ret2 = ", ret2)
ret1 = nil
ret2 = nil

------------- ret_table_test --------------
local t3 = ret_table_test()
print("t3 = ", t3)
for i, v in pairs(t3) do
    print(i .. " => " .. v)
end

t3 = nil

------------- getLuaVar_test --------------
g_var1 = 13.4

----------- getLuaVar_table_test -------------
g_t1 = {
    name = "王五", age = 22,
}

g_t2 = {
    { name = "张三", age = 21 },
    { name = "王五", age = 22 },
    { name = "李明", age = 12 },
}

---------- set2LuaVar_test -------------
print(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>  lua get c++ global var")
print("c++ g_name = " .. g_name)

----------- setLuaVar_table_test ------------
print(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>  lua get c++ global table var")
print("g_varTable ==> ", g_varTable)
print("g_varTable name ==> " .. g_varTable["name"])

----------- callLuaFunc_simple -------------

function luaSimpleFunc1()
    -- 测试错误用
    --function luaSimpleFunc()
    print("c++ call lua func simple")
end

---------------- callLuaFunc_params_ret -------------------
--function luaParamsAndRetFunc1(name, age, t)  -- 测试错误用
function luaParamsAndRetFunc(name, age, t)
    --function luaSimpleFunc()
    print("c++ call lua params and ret func")
    print("name = ", name, "  age = ", age, "  t = ", t, "  t.score = ", t.score)
    local retTable = { name = "saber", age = 20 }
    return "this is a lua params_return func return", retTable
end

function fError(e)
    print("原始Error = ", e)
    return "这是自定义错误处理函数返回的错误,将覆盖原始返回的错误"
end

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值