如何解决C代码读取Lua表时遍历顺序随机的问题?
如何在C代码中按固定顺序读取Lua表MP_STATS
当前使用lua_next遍历Lua表MP_STATS时,读取顺序完全随机,无法按表定义的顺序读取。
Lua表定义
MP_STATS = { ENABLE = true, NOBLOCK = false, RECOVERY = false, EXPERIENCE = true, -- 其他字段 }
当前C代码示例
void read_test(void){ lua_State *L; L = luaL_newstate(); luaL_openlibs(L); if (luaL_loadfile(L, "test.lua") || lua_pcall(L, 0, 0, 0)) { ShowError("Error reading 'test.lua'\n"); return; } lua_getglobal(L, "MP_STATS"); lua_pushnil(L); while (lua_next(L, 1) != 0) { const char *name = lua_tostring(L, 2); if(check_exist_stats(name) == 0) { printf("Stats %s not exist.\n", name); lua_pop(L, 1); continue; } lua_getfield(L, lua_gettop(L), name); myvar = lua_toboolean(L, lua_gettop(L)); lua_pop(L, 1); printf("%s\n", name); } lua_close(L); printf("Read test.lua complete.\n"); }
问题现象
多次运行程序,输出顺序随机:
第一次运行输出:
MP_NOBLOCK MP_ENABLE MP_EXPERIENCE MP_RECOVERY
第二次运行输出:
MP_RECOVERY MP_ENABLE MP_NOBLOCK MP_EXPERIENCE
第三次运行输出:
MP_ENABLE MP_NOBLOCK MP_EXPERIENCE MP_RECOVERY
解决方案
Lua的普通表是哈希表结构,lua_next的遍历顺序是随机的(从Lua 5.1开始引入随机化哈希遍历),要实现固定顺序读取,有两种可靠方式:
方法一:在Lua表中维护顺序数组
修改Lua表,增加一个存储键顺序的数组字段(比如_ORDER),C代码先读取这个数组,再按数组中的顺序逐个获取对应字段的值。
修改后的Lua表:
MP_STATS = { _ORDER = {"ENABLE", "NOBLOCK", "RECOVERY", "EXPERIENCE"}, -- 定义固定顺序 ENABLE = true, NOBLOCK = false, RECOVERY = false, EXPERIENCE = true, -- 其他字段 }
对应的C代码修改:
void read_test(void){ lua_State *L; L = luaL_newstate(); luaL_openlibs(L); if (luaL_loadfile(L, "test.lua") || lua_pcall(L, 0, 0, 0)) { ShowError("Error reading 'test.lua'\n"); return; } lua_getglobal(L, "MP_STATS"); // 读取_ORDER数组 lua_getfield(L, -1, "_ORDER"); if (!lua_istable(L, -1)) { ShowError("MP_STATS._ORDER is not a table\n"); lua_close(L); return; } // 遍历顺序数组 size_t i = 1; lua_pushinteger(L, i); while (lua_rawget(L, -2) != LUA_TNIL) { const char *name = lua_tostring(L, -1); if (name == NULL) { lua_pop(L, 1); i++; lua_pushinteger(L, i); continue; } if (check_exist_stats(name) == 0) { printf("Stats %s not exist.\n", name); lua_pop(L, 1); i++; lua_pushinteger(L, i); continue; } // 获取对应字段的值 lua_getfield(L, -3, name); // -3是MP_STATS表的位置 myvar = lua_toboolean(L, -1); printf("%s\n", name); lua_pop(L, 2); // 弹出值和当前数组元素 i++; lua_pushinteger(L, i); } lua_pop(L, 2); // 弹出数组元素(nil)和_ORDER表 lua_close(L); printf("Read test.lua complete.\n"); }
方法二:在C代码中预先定义固定顺序的键列表
如果无法修改Lua代码,直接在C代码里定义一个包含所有目标键的数组,按顺序遍历这个数组,用lua_getfield逐个读取对应的值。
修改后的C代码:
void read_test(void){ lua_State *L; L = luaL_newstate(); luaL_openlibs(L); // 预先定义固定顺序的键列表 const char *stats_order[] = {"ENABLE", "NOBLOCK", "RECOVERY", "EXPERIENCE", NULL}; if (luaL_loadfile(L, "test.lua") || lua_pcall(L, 0, 0, 0)) { ShowError("Error reading 'test.lua'\n"); return; } lua_getglobal(L, "MP_STATS"); if (!lua_istable(L, -1)) { ShowError("MP_STATS is not a table\n"); lua_close(L); return; } // 遍历预定义的键列表 for (int i = 0; stats_order[i] != NULL; i++) { const char *name = stats_order[i]; if (check_exist_stats(name) == 0) { printf("Stats %s not exist.\n", name); continue; } lua_getfield(L, -1, name); if (lua_isboolean(L, -1)) { myvar = lua_toboolean(L, -1); printf("%s\n", name); } else { printf("Stats %s has invalid value type\n", name); } lua_pop(L, 1); } lua_close(L); printf("Read test.lua complete.\n"); }
内容的提问来源于stack exchange,提问作者alberto silva
相关产品推荐
相关产品推荐

