Lua/C++ - 尝试遍历表时出现的lua_next()段错误

我在 C++ 中有以下代码:

lua_getglobal(C, "theTable");
lua_pushnil(C);
while (lua_next(C, -2) != 0) {
  /* snip */
}

然而,当它运行时,会报告 segfault。LLDB 的停止消息如下。

* thread #1: tid = 0x50663f, 0x000000000002b36a luaos`luaH_next + 58, queue =
'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x38)
frame #0: 0x000000000002b36a luaos`luaH_next + 58

Luaos 是可执行文件名。为了可移植性,我已将 Lua 直接编译到可执行文件中。

附注:C 是 lua 状态的名称。它是我的第二个配置 lua 状态(与我的主要代码 lua 状态 L 相对),这就是命名背后的原因。

点赞
用户107090
用户107090

我看到了三个潜在的问题:

  • 全局变量theTable不存在,位置 -2 上有一个空值。

  • 在循环中你使用lua_tostring将键转换为字符串,也许是为了打印。手册 这会让lua_next混淆。

  • 在第一次循环迭代后,位置-2上有其他值。请注意,lua_next将两个值推入栈中,即键和值。在再次调用lua_next之前,您需要将键保留在堆栈顶部。而且,确保表位于位置-2。可能最好在lua_getglobal之后将-2转换为绝对位置。但你仍然需要在每次迭代后将lua_next返回的键留在堆栈顶部。

2014-09-16 10:01:23
用户929395
用户929395

似乎您的代码只是部分正确的,我将详细说明如何使用lua_next,包括您的代码正确的部分。

lua_next希望栈中至少有两个元素(以以下顺序):

[1] 上一个键
...
[t] table

在第一次调用函数时,previous key应为nil,因此函数将把第一个键值对推送到栈中,并开始遍历。

lua_getglobal(L, "theTable"); // 栈中的表
// ...
lua_pushnil(L);               // 压入nil
lua_next(L, t);               // t是theTable索引

调用lua_next后,弹出先前的键并将键值对推送到栈中,如下所示:

[1] 值
[2] 键
...
[t] -- 未知值 --
[t+1] table

如果使用此栈再次调用函数,则value作为当前键,table作为未知值,因此会发生错误。为了避免这种情况,应该弹出栈顶的[1] value

lua_pop(L, 1); // 弹出值

现在栈中将具有继续遍历所需的预期值,lua_next可以再次调用。当表中没有更多元素时,函数将返回0。

这是一个完整的例子:

lua_getglobal(L, "theTable"); // 栈中的表
lua_pushnil(L);               // 压入nil
while(lua_next(L, -2) != 0) {
    // 处理key-value对
    lua_pop(L, 1); // 弹出值
}
2017-01-03 05:00:17