零、前言
Lua 作为一门脚本语言,可以作为 “配置文件”、“动态逻辑脚本” 等角色作用于宿主程序。
因为他是一门语言,所以他有以下的好处:
1. Lua 会处理语法细节,后续维护简单,并且可以有注释。
2. 可以编写逻辑,达到复杂的配置。
如果我们的程序需要进行一些 “下发配置” 时,一般会考虑选择 “json”、“文件” 等形式。但是如果 “配置” 内容较为复杂,则可以考虑 Lua 了,具体可以查看以下分享。
一、运行 Lua 文件
在之前 “C++ 与 Lua 交互异常处理” 的文章中,已分享如何在 C/C++ 中使用 Lua 文件,这里复习一下。
可以通过 lua_call
和 lua_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
接下来看宿主如何运行和调用,可以结合着注释理解。思路是:
- 使用
luaL_loadfile
加载 Lua 文件 - 使用
lua_pcall
运行 Lua 文件,此时 Lua 中的luaFunction
是一个全局变量 - 将
luaFunction
压入栈,同时将需要传递的参数压入栈,然后通过lua_pcall
调用函数 - 最后使用出栈函数获取结果,因为这里为数值,所以使用
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