lua 报错处理

lua 报错处理

在给 c++ 程序集成lua库后,使用lua 时,难免会写出来lua 语法级的错误,运行时的错误。这时候就需要 c++ 程序能够对 lua 的错误有所处理,明确地把错误内容显示出来。

c++中获取 lua 错误

lua 库本身,许多函数都可能会返回一个 int 值,如果这个值不是0,则代表 在执行 lua 脚本时,遇到了错误。
比如 luaL_loadfile() lua_pcall() 等

这个返回值,代表一种 lua 错误。 lua 的错误类型定义在

lua.h

/* thread status; 0 is OK */
#define LUA_YIELD   1
#define LUA_ERRRUN  2
#define LUA_ERRSYNTAX   3
#define LUA_ERRMEM  4
#define LUA_ERRERR  5

有这么多种类的 lua 错误,但总之只要返回值是0,就代表没错。

在返回值不是0的情况下,会把 lua 错误的具体内容 放到 lua 栈的栈顶。可以通过把 lua 栈的栈顶元素 lua_tostring() ,把这个内容打印出来,这个字符串就是 lua 报错的内容了。

在此参考 lua程序设计第2版,谢了一个 stackDump()函数,打印出来 lua 和 c语言交互栈的所有内容,便于在lua 报错时,观察 lua 报错的内容。

std::string LuaWrapper::stackDump()
{
    int stackSize = lua_gettop(_luaState);

    std::string allInfo;
    for (int index = 1;index <= stackSize;index++)
    {
        int t = lua_type(_luaState, index);
        std::string strInfo;
        switch (t)
        {
            case LUA_TSTRING: 
            {
                strInfo = lua_tostring(_luaState, index);   
                break;
            }
            case LUA_TBOOLEAN:
            {
                strInfo = lua_toboolean(_luaState, index) ? "true" : "false";
                break;
            }
            case LUA_TNUMBER:
            {
                lua_Number result = lua_tonumber(_luaState, index);
                std::stringstream ss;
                ss << result;
                ss >> strInfo;
                break;
            }
            default:
            {
                strInfo = lua_typename(_luaState, index);
                break;
            }
        };
        allInfo = allInfo + strInfo.c_str() + "\n";
        printf("%s\t",strInfo.c_str());
    }
    return allInfo;
}

由此,可以在 c++ 调用 lua 函数、执行 lua 文件后,根据返回值,来判断是否有 lua 错误,从而对其进行处理。
例:

int err = luaL_loadfile(_luaState, filepath.c_str()) || lua_pcall(_luaState, 0, LUA_MULTRET, 0);
    if (err != 0)
    {
        std::string info = stackDump();
        errorHandler(info);
    }

lua中处理 lua 错误

上面例子中,会直接执行一个 lua 文件里的 内容。这里的 lua 文件代码如下:

main.lua

print("gogo1go");

function _G_GLOBAL_TRACEBACK_(msg)
    local allErrInfo = "Error: " .. msg .. "\n" .. "Stack: " .. debug.traceback();
    print(allErrInfo);
    LuaWrapper:getInstance():errorHandler(allErrInfo)
end


function traceback()
    for level = 1,math.huge do
        local info = debug.getinfo(level);
        if not info then break end
        if info.what == "C" then
            print(level,"C function");
        else
            print(string.format("[%s]:%d",info.short_src,info.currentline));
        end
    end
end

function main()
    print("main");
    traceback()
    local instance = MyClass:new();
    instance:testFunc();
    instance:delete();
    print(tostring(LuaWrapper:getInstance()._testValue));
end

xpcall(main,_G_GLOBAL_TRACEBACK_);

上面的lua 文件中,直接通过 xpcall 执行 main() lua函数。

如果运行时有 lua 错误,则会进入 _G_GLOBAL_TRACEBACK_
有了 xpcall 对 lua 进行错误处理的话,在 lua 触发错误后,lua_pcall(_luaState, 0, LUA_MULTRET, 0); 的返回值 err 就不大于0了,因为在 lua 一层已经处理了 lua 的错误。

如果此时依然希望借助 c++ 处理 lua 错误,则需要在 _G_GLOBAL_TRACEBACK_ 手动调用 c++ 错误处理函数。

LuaWrapper:getInstance():errorHandler(allErrInfo)

lua报错的处理形式

class LuaWrapper 里,我实现了一个函数,用于统一处理 lua报错。并且把这个函数用 tolua++ 导出过,因此 无论是 c++ 里触发了 lua 错误,还是 lua 里面处理了 lua 错误,都可以调用此函数 做错误处理。

void LuaWrapper::errorHandler(std::string errMsg)
{
#ifdef WIN32
    std::wstring errMsgW = StringToWString(errMsg);
    MessageBox(nullptr, errMsgW.c_str(),L"lua error!", MB_OK);
#endif //WIN32
}

根据应用场景的不同,错误处理的形式也不一样。

在游戏开发的情况下,我比较推荐把错误非常明显的现出来。如果仅仅是把lua 错误堆栈和信息打印出来,很可能早出触发了错误而不知,后面的逻辑整体混乱,导致错误难于排查。

因此, 在 win32 平台下,通过 MessageBox() 来显示一个 明显的错误比较合适。

Android 下使用 AlertDialog,iOS下使用 UIAlertController ,都可以达到把错误明显显示出来的目的。

例如,在 main.lua 里随便写一个 错误 (第5行)

print("gogo1go");


fdsfd

function _G_GLOBAL_TRACEBACK_(msg)
    local allErrInfo = "Error: " .. msg .. "\n" .. "Stack: " .. debug.traceback();
    print(allErrInfo);
    LuaWrapper:getInstance():errorHandler(allErrInfo)
end


function traceback()
    for level = 1,math.huge do
        local info = debug.getinfo(level);
        if not info then break end
        if info.what == "C" then
            print(level,"C function");
        else
            print(string.format("[%s]:%d",info.short_src,info.currentline));
        end
    end
end

function main()
    print("main");
    traceback()
    local instance = MyClass:new();
    instance:testFunc();
    instance:delete();
    print(tostring(LuaWrapper:getInstance()._testValue));
end

xpcall(main,_G_GLOBAL_TRACEBACK_);

则会调用 void LuaWrapper::errorHandler(std::string errMsg) 函数,显示一个非常明显的错误提示:
win32处理lua报错截图

相关文章
相关标签/搜索