如何在C/C++中读取Lua嵌套表的键与值?
问题描述
我有如下Lua脚本,调用了一个C++函数,需要读取嵌套Lua表的键与值:
local scenariolist = { scenarios = { 'scenario1', 'scenario3', 'scenario2' }, result = true, message = 'test message' } my.sendfromscenariolist(scenariolist)
对应的初始C++实现如下:
int ScenarioFunction(lua_State* L) { int nargs = lua_gettop(L); if (nargs != 1) { return 0; } int type = lua_type(L, 1); if (type != LUA_TTABLE) { return 0; } ParseScenarioTable(L); return 0; } void ParseScenarioTable(lua_State* L) { lua_pushnil(L); while (lua_next(L, -2) != 0) { if (lua_istable(L, -1)) { ParseScenarioTable(L); std::cout << "Key: " << "key" << ", Value is table" << std::endl; } else if (lua_isstring(L, -1)) { std::string x = lua_tostring(L, -1); std::cout << "Key: " << "key" << ", Value: " << x << std::endl; int i = 0; } else if (lua_isboolean(L, -1)) { bool x = lua_toboolean(L, -1); int i = 0; std::cout << "Key: " << "key" << ", Value: " << x << std::endl; } lua_pop(L, 1); } }
这段代码只能读取值,输出如下:
Key: key, Value: 1 Key: key, Value: scenario1 Key: key, Value: scenario3 Key: key, Value: scenario2 Key: key, Value is table Key: key, Value: test message
为了读取键,我修改了代码:
int ScenarioFunction(lua_State* L) { int nargs = lua_gettop(L); if (nargs != 1) { return 0; } int type = lua_type(L, 1); if (type != LUA_TTABLE) { return 0; } ParseScenarioTable(L); return 0; } void ParseScenarioTable(lua_State* L) { lua_pushnil(L); while (lua_next(L, -2) != 0) { if (lua_istable(L, -1)) { std::string key = lua_tostring(L, -2); ParseScenarioTable(L); std::cout << "Key: " << key << ", Value is table" << std::endl; } else if (lua_isstring(L, -1)) { std::string key = lua_tostring(L, -2); std::string x = lua_tostring(L, -1); std::cout << "Key: " << key << ", Value: " << x << std::endl; int i = 0; } else if (lua_isboolean(L, -1)) { std::string key = lua_tostring(L, -2); bool x = lua_toboolean(L, -1); int i = 0; std::cout << "Key: " << key << ", Value: " << x << std::endl; } lua_pop(L, 1); } }
但运行时出现错误:
Key: result, Value: 1 Key: 1, Value: scenario1 [2023-09-01 16:17:03.391093][error]: Error when running the script. Error is: invalid key to 'next'
请问哪里出错了?如何正确读取嵌套Lua表的键与值?
错误原因与解决方案
错误原因
核心问题是嵌套递归调用ParseScenarioTable时破坏了lua_next依赖的栈状态:
- 调用
lua_next(L, -2)后,栈结构为[表, 键, 值]。当值是子表时,你直接递归调用ParseScenarioTable(L),这个递归函数会在当前栈顶的子表上执行遍历操作,遍历完成后栈结构被修改,外层lua_next无法找到正确的后续键,最终触发"invalid key to 'next'"错误。 - 额外问题:Lua表的键可能是数字类型(如数组式表的索引),直接用
lua_tostring转换数字键虽能得到字符串,但类型处理不够严谨。
修正后的代码
#include <iostream> #include <string> extern "C" { #include <lua.h> #include <lauxlib.h> #include <lualib.h> } int ScenarioFunction(lua_State* L) { int nargs = lua_gettop(L); if (nargs != 1 || !lua_istable(L, 1)) { return 0; } ParseScenarioTable(L); return 0; } // 辅助函数:将不同类型的键转换为字符串表示 std::string GetKeyString(lua_State* L, int index) { std::string keyStr; switch (lua_type(L, index)) { case LUA_TSTRING: keyStr = lua_tostring(L, index); break; case LUA_TNUMBER: keyStr = std::to_string(lua_tonumber(L, index)); break; case LUA_TBOOLEAN: keyStr = lua_toboolean(L, index) ? "true" : "false"; break; default: keyStr = lua_typename(L, lua_type(L, index)); break; } return keyStr; } void ParseScenarioTable(lua_State* L) { // 固定当前表的栈索引,避免嵌套调用时栈偏移混乱 int tableIndex = lua_gettop(L); lua_pushnil(L); while (lua_next(L, tableIndex) != 0) { // 当前栈结构:[表, 键, 值] std::string key = GetKeyString(L, -2); if (lua_istable(L, -1)) { // 递归处理子表,完成后栈会恢复到当前状态 ParseScenarioTable(L); std::cout << "Key: " << key << ", Value is table" << std::endl; } else if (lua_isstring(L, -1)) { std::string value = lua_tostring(L, -1); std::cout << "Key: " << key << ", Value: " << value << std::endl; } else if (lua_isboolean(L, -1)) { bool value = lua_toboolean(L, -1); std::cout << "Key: " << key << ", Value: " << (value ? "true" : "false") << std::endl; } else if (lua_isnumber(L, -1)) { double value = lua_tonumber(L, -1); std::cout << "Key: " << key << ", Value: " << value << std::endl; } // 弹出值,栈回到[表, 键],供下一次lua_next使用 lua_pop(L, 1); } }
关键修正点
- 固定表的栈索引:进入循环前用
tableIndex = lua_gettop(L)记录当前表的位置,后续lua_next使用这个固定索引,避免嵌套调用导致的栈偏移错误。 - 递归栈状态保护:递归调用
ParseScenarioTable时,栈顶是子表,递归完成后栈会自动恢复到调用前的状态,不会破坏外层lua_next的执行环境。 - 完善键类型处理:新增
GetKeyString辅助函数,支持字符串、数字、布尔等多种类型键的转换,避免类型转换异常。 - 代码简洁优化:合并初始参数检查逻辑,减少冗余代码。
运行输出
修正后会得到正确的键值输出:
Key: result, Value: true Key: scenarios, Value is table Key: 1, Value: scenario1 Key: 2, Value: scenario3 Key: 3, Value: scenario2 Key: message, Value: test message
内容的提问来源于stack exchange,提问作者Jepessen
相关产品推荐
相关产品推荐

