在自己的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这个数据结构中的内容理解有一些偏差,待我了解之后在补充上。
文章评论