在嵌入Lua的C代码中打印堆栈跟踪信息。

如果我理解正确的话,Lua默认在发生错误时会调用"debug.traceback"调试库。

然而,当在C代码中嵌入Lua,例如在这里的示例中: Simple Lua API Example

我们仅仅有在栈顶上的错误信息可用。

例如:

if (status) {
    /* 如果出了什么问题,错误信息就在栈顶 */
    fprintf(stderr, "Couldn't load file: %s\n", lua_tostring(L, -1));

    /* 我想在这里打印一个堆栈跟踪,该怎么做呢? */
    exit(1);
}

在初始错误后,如何从C中打印堆栈跟踪?

点赞
用户734069
用户734069

默认情况下,Lua 在出现错误时会调用 debug 库中的 "debug.traceback" 函数。

不,它不会。Lua 运行时 (lua.exe) 会这么做,但 Lua 库本身不会自行执行此操作。如果想在 Lua 错误时获得调用栈,就需要自己生成。

Lua 运行时通过使用 lua_pcall 的错误函数来实现这一点。当错误函数被调用时,栈未被展开,因此在此处可以获得一个堆栈跟踪。运行时使用的错误函数如下:

static int traceback (lua_State *L) {
  if (!lua_isstring(L, 1))  /* 'message' not a string? */
    return 1;  /* keep it intact */
  lua_getfield(L, LUA_GLOBALSINDEX, "debug");
  if (!lua_istable(L, -1)) {
    lua_pop(L, 1);
    return 1;
  }
  lua_getfield(L, -1, "traceback");
  if (!lua_isfunction(L, -1)) {
    lua_pop(L, 2);
    return 1;
  }
  lua_pushvalue(L, 1);  /* pass error message */
  lua_pushinteger(L, 2);  /* skip this function and traceback */
  lua_call(L, 2, 1);  /* call debug.traceback */
  return 1;
}
2012-09-04 03:47:15
用户6444
用户6444

以下是一个可运行的例子,基于Nicol的答案:

static int traceback(lua_State *L) {
    lua_getfield(L, LUA_GLOBALSINDEX, "debug"); // 获取debug表
    lua_getfield(L, -1, "traceback"); // 获取traceback函数
    lua_pushvalue(L, 1); // 压入错误对象
    lua_pushinteger(L, 2); // 错误级别为2
    lua_call(L, 2, 1); // 调用traceback函数
    fprintf(stderr, "%s\n", lua_tostring(L, -1)); // 输出错误信息到标准错误输出
    return 1;
}

int main(int argc, char **argv) {
    lua_State *L = lua_open(); // 打开Lua虚拟机
    luaL_openlibs(L); // 加载Lua标准库
    lua_pushcfunction(L, traceback); // 将traceback函数压入栈顶
    int rv = luaL_loadfile(L, "src/main.lua"); // 加载Lua代码文件
    if (rv) {
        fprintf(stderr, "%s\n", lua_tostring(L, -1)); // 输出错误信息到标准错误输出
        return rv;
    } else {
        return lua_pcall(L, 0, 0, lua_gettop(L) - 1); // 调用Lua函数
    }
}
2013-05-01 17:41:05
用户3529665
用户3529665
mxcl 的代码有些问题:

static int traceback(lua_State *L) { lua_getfield(L, LUA_GLOBALSINDEX, "debug"); lua_getfield(L, -1, "traceback"); //--------------------------- lua_pop(L,-2); //弹出'debug' //--------------------------- lua_pushvalue(L, 1); lua_pushinteger(L, 2); lua_call(L, 2, 1); fprintf(stderr, "%s\n", lua_tostring(L, -1)); return 1; }

```

2014-04-13 18:48:29
用户2396213
用户2396213

我遇到了和你一样的问题,我发现以下的方法可以解决:

luaL_traceback(L, L, NULL, 1);
printf("%s\n", lua_tostring(L, -1));

由于luaL_tracebackdebug.traceback()已经很相似了,它用于打印堆栈,因此我认为这是一种适当的方式,你可以阅读luaL_traceback的API手册,或者直接阅读 Lua 的源代码来弄清参数的含义。

2015-09-16 09:10:41