在自己的C++中调用lua脚本时,遇到了一个比较麻烦的问题。因为在lua脚本中有调用C++提供的一些函数导致lua脚本再正常的lua运行环境中是没办法调试运行,但是不调试运行的脚本会有很多问题,比如语法错误,或者运行时的逻辑错误导致表的索引越界。最开始遇到这些问题的时候我只能在脚本中写相当多的print,这样来调试,但是后面脚本越写越复杂这样的调试方法效率就相当低了。
然后谷歌了一下,发现lua本身在运行脚本之前本来就会检查
lua语法错误静态检查
一般在调用脚本之前我们会用luaL_dostring()或者luaL_dofile()载入脚本。这两个函数在载入脚本时会检查脚本的语法是否正确,如果发现语法错误会返回非0值,并且将语法错误压入栈顶。我们想要获取错误提示直接获取栈顶的数据就可以了。
- C++代码
lua_State * L= nullptr;
/* 初始化 Lua */
L = luaL_newstate();
/* 载入Lua基本库 */
luaL_openlibs(L);
/* 运行脚本 */
int ok = luaL_dofile(L,"./hello.lua");
if(ok != 0)
{
//检查栈顶数据是否为字符串,否则退出
int type = lua_type(L,-1);
if(type != 4)
return;
std::string error = lua_tostring(L,-1);
std::cout << error;
}
- lua代码
function hello()
printd("hello world");
end
因为我在lua脚本中没有在函数的结尾加上end,所以运行结果是
其实我这里的print也故意写错了,尝试了一下函数名或者变量名写错了再这里并不会报错。
C++代码中用了lua_type判断栈中数据的类型,以下是所有数据类型的定义
#define LUA_TNIL 0 #define LUA_TBOOLEAN 1 #define LUA_TLIGHTUSERDATA 2 #define LUA_TNUMBER 3 #define LUA_TSTRING 4 #define LUA_TTABLE 5 #define LUA_TFUNCTION 6 #define LUA_TUSERDATA 7 #define LUA_TTHREAD 8
运行时的错误捕获
lua_call()是一个用于调用lua脚本中指定函数的函数(好像有点绕)。
它的原型是这样int lua_call(lua_state,fparaCount,returnCount) .这个函数并不提供运行时的错误捕获功能。我们得用和它名字很像的lua_pcall(),让我们可以指定一个错误处理的回调函数。所以我们可以利用它来捕获lua运行时的错误。
- C++代码
//错误回调
int LuaErrorCallBack(lua_State *L)
{
lua_Debug debug = {};
//错误所处的的调用层级
int rank = 0;
//逐层获取lua抛出的错误,直到获取到
while (lua_getstack(L,rank,&debug)) {
rank ++;
}
//判断栈顶是否为字符串类型
int type = lua_type(L,-1);
if(type != 4)
return 0;
std::string error = lua_tostring(L,-1);
std::string errorShort = debug.short_src;
int errorLine = debug.currentline;
std::string errorMsg = "error:" + error + ",errorShort:" + errorShort
+ ",line:" + std::to_string(errorLine);
//将错误信息压人栈
lua_pushstring(L,errorMsg.c_str());
return 1;
}
int main()
{
lua_State * L= nullptr;
/* 初始化 Lua */
L = luaL_newstate();
/* 载入Lua基本库 */
luaL_openlibs(L);
/* 运行脚本 */
int ok = luaL_dofile(L,"./hello.lua");
if(ok != 0)
{
//检查栈顶数据是否为字符串,否则退出
int type = lua_type(L,-1);
if(type != 4)
return;
std::string error = lua_tostring(L,-1);
std::cout << error;
}
//将错误处理函数压入栈
lua_pushcfunction(L,LuaErrorCallBack);
//获取栈顶的位置即错误回调函数的位置
int callBack = lua_gettop(L);
lua_getglobal(L,"hello");
ok = lua_pcall(L,0,0,callBack);
if(ok != 0)
{
std::string error = lua_tostring(L,-1);
std::cout << error << std::endl;
}
lua_close(L);
}
- lua代码
function hello()
printf("hello");
end
- 运行结果
看这次我又把print写错了,不过这次你终于发现了。
不过看这里的输出信息,我对lua_debug这个数据结构中的内容理解有一些偏差,待我了解之后在补充上。
文章评论