C++ 调用 Lua 函数

本文详细介绍了如何在 C++ 中调用 Lua 文件并使用 lua_getglobal、lua_newtable、lua_createtable、lua_gettable、lua_getfield、lua_settable 和 lua_setfield 等函数来操作 Lua 的全局变量和表,以实现宿主程序与 Lua 脚本的交互。示例展示了如何根据环境执行不同逻辑和预设配置,以及如何处理 Lua 中的配置文件。
摘要由CSDN通过智能技术生成

零、前言

Lua 作为一门脚本语言,可以作为 “配置文件”、“动态逻辑脚本” 等角色作用于宿主程序。

因为他是一门语言,所以他有以下的好处:

1. Lua 会处理语法细节,后续维护简单,并且可以有注释。
2. 可以编写逻辑,达到复杂的配置。

如果我们的程序需要进行一些 “下发配置” 时,一般会考虑选择 “json”、“文件” 等形式。但是如果 “配置” 内容较为复杂,则可以考虑 Lua 了,具体可以查看以下分享。

一、运行 Lua 文件

在之前 “C++ 与 Lua 交互异常处理” 的文章中,已分享如何在 C/C++ 中使用 Lua 文件,这里复习一下。

可以通过 lua_calllua_pcall 两个函数调用 Lua 代码。

int lua_call(lua_State *L, int nargs, int nresults);

int lua_pcall(lua_State *L, int nargs, int nresults, int errfunc);

两者均用于在 C/C++ 代码中调用 Lua 函数,不同点在于:

  • lua_call 会将代码中的异常直接抛出,导致程序中断。
  • lua_pcall 提供一个保护模式运行 Lua 代码,即使发生异常,也会被捕获,并可以通过第四个参数的错误处理函数处理错误,程序不会因此而中断。

参数:

  • 参数 L: Lua State 的指针。
  • 参数 nargs: 传递给被调用函数的参数个数。
  • 参数 nresults: 期望的返回值个数。
  • 参数 errfunc: 错误处理函数的索引,用于处理发生的错误。如果为 0,则错误信息会被压入栈顶。

返回值:

  • 函数调用成功,返回 0,并将返回值压入栈中。
  • 如果函数调用发生错误,返回一个非零值,并将错误信息压入栈中。

错误处理的细节可以翻阅之前的 “C++ 与 Lua 交互异常处理” 文章。

举个例子

我们通过 lua_pcall 加载一个 Lua 文件,然后在调用 Lua 中的一个函数计算数值,最后获取返回结果。

Lua 文件的内容

function luaFunction(x, y)
    return (x ^ 2 * math.sin(y)) / (1 - x)
end

接下来看宿主如何运行和调用,可以结合着注释理解。思路是:

  1. 使用 luaL_loadfile 加载 Lua 文件
  2. 使用 lua_pcall 运行 Lua 文件,此时 Lua 中的 luaFunction 是一个全局变量
  3. luaFunction 压入栈,同时将需要传递的参数压入栈,然后通过 lua_pcall 调用函数
  4. 最后使用出栈函数获取结果,因为这里为数值,所以使用 lua_tonumberx 出栈函数
// C++ 入口
void cppCallLuaFunction() {
   
    std::string fname = PROJECT_PATH + "/5、C++调用Lua代码/调用Lua函数/调用Lua函数.lua";
    lua_State *L = luaL_newstate();
    luaL_openlibs(L);

    // 加载 Lua 文件、运行 Lua 文件
    if (luaL_loadfile(L, fname.c_str()) || lua_pcall(L, 0, 0, 0)) {
   
        printf("can't run config. file: %s\n", lua_tostring(L, -1));
        lua_close(L);
        return;
    }

    double calResult = 0;
    bool isSuccess = false;
    // 调用 Lua 文件中的函数
    isSuccess = callLuaFunction(L, 2, 34, &calResult);
    if (isSuccess) {
   
        printf("调用 Lua 成功 luaFunction: %f\n", calResult);
    } else {
   
        printf("调用 Lua 失败\n");
    }

    lua_close(L);
}

// 调用 Lua 函数
bool callLuaFunction(lua_State *L, double x, double y, double *result) {
   
    // 获取全局中的 luaFunction 变量,将其压入栈中
    int getResult = lua_getglobal(L, "luaFunction");
    if (getResult == LUA_TNIL) {
   
        printf("lua_getglobal get failure\n");
        return false;
    }
    // 将 x 和 y 入栈,会作为 luaFunction 函数的两个参数
    lua_pushnumber(L, x);
    lua_pushnumber(L, y);

    // 运行 luaFunction 函数
    if (lua_pcall(L, 2, 1, 0) != LUA_OK) {
   
        printf("error running function 'f': %s", lua_tostring(L, -1));
        return false;
    }

    int isNum;
    // 获取 luaFunction 的返回值
    *result = lua_tonumberx(L, -1, &isNum);
    if (!isNum) {
   
        printf("function 'luaFunction' s
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值