如何从 C++ 读取和写入嵌套的 lua 表?

Posted

技术标签:

【中文标题】如何从 C++ 读取和写入嵌套的 lua 表?【英文标题】:How can I read and write to nested lua tables from C++? 【发布时间】:2021-10-09 22:20:40 【问题描述】:

我的 lua 代码中有一个嵌套表,我想将它传递给 C++,以便本机代码可以对其进行操作:

-- Some persistent data in my game
local data = 
         44, 34, 0, 7, ,
         4, 4, 1, 3, ,

-- Pass it into a C++ function that can modify the input data.
TimelineEditor(data)

如何编写 C++ 代码来读取嵌套表并修改其值?

Reading Lua nested tables in C++ 和 lua c read nested tables 都描述了我如何从嵌套表中读取,但没有描述如何写入它们。

【问题讨论】:

这能回答你的问题吗? Reading Lua nested tables in C++ 这个问题只是关于读取表格,而不是写入表格。 您可以考虑在您的项目中包含 sol 库。它会让生活更轻松 正确,尽管我敢肯定任何能做到这一点的人都可以使用lua_rawseti 而不是lua_rawgeti。而且由于存在关于如何读取嵌套表(以及写入常规表)的问题,因此真的不需要这个问题吗?但我猜是公平的。 有3 other q/a with rawseti,它们要么是关于非嵌套表,要么是创建新表。我与 rawseti 建立了联系,但花了一段时间才弄清楚细节。我认为这个问题对于任何试图了解 lua C API 是如何工作的人都会非常有帮助。 【参考方案1】:

简答

Lua 使用堆栈来获取表中的值。要修改表值,您需要使用lua_rawgeti 推送要修改的表,使用lua_pushinteger 推送要插入的值,然后使用lua_rawseti 在表中设置值。

在编写本文时,重要的是可视化堆栈以确保您使用正确的索引:

lua_rawgeti()
    stack:
        table

lua_rawgeti()
    stack:
        number <-- top of the stack
        table

lua_tonumber()
    stack:
        number
        table

lua_pop()
    stack:
        table

lua_pushinteger()
    stack:
        number
        table

lua_rawseti()
    stack:
        table

负索引是堆栈位置,正索引是参数位置。所以我们经常会通过 -1 来访问堆栈中的表。当调用lua_rawseti 写入表时,我们将传递-2,因为表低于我们正在写入的值。

示例

我将在 lua 代码中添加inspect.lua 以打印出表值,以便我们可以看到这些值已被修改。

local inspect = require "inspect"

local data = 
         44, 34, 0, 7, ,
         4, 4, 1, 3, ,

print("BEFORE =", inspect(data,  depth = 5, ))
TimelineEditor(data)
print("AFTER =", inspect(data,  depth = 5, ))

假设你已经找到BindingCodeToLua,你可以像这样实现这个函数:


// Replace LOG with whatever you use for logging or use this:
#define LOG(...) printf(__VA_ARGS__); printf("\n")

// I bound with Lunar. I don't think it makes a difference for this example.
int TimelineEditor(lua_State* L)

    LOG("Read the values and print them out to show that it's working.");
    
        int entries_table_idx = 1;
        luaL_checktype(L, entries_table_idx, LUA_TTABLE);
        int n_entries = static_cast<int>(lua_rawlen(L, entries_table_idx));
        LOG("%d entries", n_entries);
        for (int i = 1; i <= n_entries; ++i)
        
            // Push inner table onto stack.
            lua_rawgeti(L, entries_table_idx, i);
            int item_table_idx = 1;
            luaL_checktype(L, -1, LUA_TTABLE);
            int n_items = static_cast<int>(lua_rawlen(L, -1));
            LOG("%d items", n_items);
            for (int i = 1; i <= n_items; ++i)
            
                // Push value from table onto stack.
                lua_rawgeti(L, -1, i);
                int is_number = 0;
                // Read value
                int x = static_cast<int>(lua_tonumberx(L, -1, &is_number));
                if (!is_number)
                
                    // fire an error
                    luaL_checktype(L, -1, LUA_TNUMBER);
                
                LOG("Got: %d", x);
                // pop value off stack
                lua_pop(L, 1);
            
            // pop table off stack
            lua_pop(L, 1);
        
    

    LOG("Overwrite the values");
    
        int entries_table_idx = 1;
        luaL_checktype(L, entries_table_idx, LUA_TTABLE);
        int n_entries = static_cast<int>(lua_rawlen(L, entries_table_idx));
        LOG("%d entries", n_entries);
        for (int i = 1; i <= n_entries; ++i)
        
            // Push inner table onto stack.
            lua_rawgeti(L, entries_table_idx, i);
            int item_table_idx = 1;
            luaL_checktype(L, -1, LUA_TTABLE);
            int n_items = static_cast<int>(lua_rawlen(L, -1));
            LOG("%d items", n_items);
            for (int j = 1; j <= n_items; ++j)
            
                int x = j + 10;
                // Push new value onto stack.
                lua_pushinteger(L, x);
                // rawseti pops the value off. Need to go -2 to get to the
                // table because the value is on top.
                lua_rawseti(L, -2, j);
                LOG("Wrote: %d", x);
            
            // pop table off stack
            lua_pop(L, 1);
        
    
    // No return values
    return 0;

输出:

BEFORE =      44, 34, 0, 7 ,  4, 4, 1, 3  
Read the values and print them out to show that it's working.
2 entries
4 items
Got: 44
Got: 34
Got: 0
Got: 7
4 items
Got: 4
Got: 4
Got: 1
Got: 3
Overwrite the values
2 entries
4 items
Wrote: 11
Wrote: 12
Wrote: 13
Wrote: 14
4 items
Wrote: 11
Wrote: 12
Wrote: 13
Wrote: 14
AFTER =       11, 12, 13, 14 ,  11, 12, 13, 14  

【讨论】:

以上是关于如何从 C++ 读取和写入嵌套的 lua 表?的主要内容,如果未能解决你的问题,请参考以下文章

Lua - C++ 集成:从 C++ 调用表中的函数

如何获取从 C++ 发送到 Lua 函数的表的更新值?

为 Lua 包装 C 库:如何创建嵌套的函数表?

如何在 C++ 中创建 Lua 表,并将其传递给 Lua 函数?

如何使用 Apache Beam (Python) 将多个嵌套的 JSON 写入 BigQuery 表

Lua C API 嵌套表段。过错