Lua/C++ - 尝试遍历表时,lua_next() 函数内部发生段错误

3

我有以下的C++代码:

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

然而,在运行时,会报告一个段错误。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` 相对),这就是取名字的原因。

你在循环中做了什么?你是在向堆栈添加元素而没有清理它们吗?你是否修改了正在遍历的表格? - Etan Reisner
我不会到意外删除键很重要的地步。是的,如果我使用正索引,这种情况会发生。 - alexbuzzbee
你在循环中使用了 lua_tostring 吗?根据手册的说明,这可能会让 lua_next 函数产生混淆。 - lhf
嗯,是的?但是再说一遍:问题在第一次迭代中。 - alexbuzzbee
你是否加载任何编译为DLL的C模块?也许你链接到多个Lua运行时... - siffiejoe
显示剩余8条评论
2个回答

5

看起来你的代码只是部分正确,我将详细解释如何使用lua_next,即使是你的代码正确的部分也会一并说明。
lua_next需要堆栈中至少有两个元素(按以下顺序):

[1] previous key
...
[t] table

在第一次调用函数时,previous key 应该是 nil ,以便函数将第一对键值对推送到堆栈中,并开始遍历。
lua_getglobal(L, "theTable"); // Stack table
// ...
lua_pushnil(L);               // Push nil
lua_next(L, t);               // t is theTable index

当调用lua_next时,它会弹出前一个键并将键值对推送到堆栈上,因此它看起来像这样:

[1] value
[2] key
...
[t] -- unknown value --
[t+1] table

如果使用这个堆栈再次调用函数,它将以当前键value和未知值table作为输入,因此会发生错误。为了避免这种情况,应弹出堆栈顶部的[1] value
lua_pop(L, 1); // Pop value

现在,堆栈中将拥有预期的值,以便继续遍历,然后可以再次调用lua_next函数。当表中没有更多元素时,该函数将返回0。
以下是一个完整的示例:

lua_getglobal(L, "theTable"); // Stack table
lua_pushnil(L);               // Push nil
while(lua_next(L, -2) != 0) {
    // Do something with key, value pair
    lua_pop(L, 1); // Pop value
}

0

我看到三个潜在的问题:

  • 全局变量theTable不存在,而在位置-2处为nil。

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

  • 第一次循环迭代后,你在位置-2有其他值。请注意,lua_next将两个值推入堆栈,即键和值。在再次调用lua_next之前,你需要将键留在堆栈顶部。并且你需要确保表仍然位于位置-2。也许更安全的做法是在lua_getglobal之后将-2转换为绝对位置lua_gettop。但是每次迭代后,你仍然需要将lua_next返回的键留在堆栈顶部。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接