C语言如何用lua_pushtable压入表?

99ANYc3cd6
预计阅读时长 29 分钟
位置: 首页 C语言 正文

Lua 的所有数据交互都通过一个虚拟栈来完成。 你不能直接操作一个 Lua 变量,而是必须把它推入栈中,然后在栈顶对它进行操作,最后可以把它赋值给一个 Lua 全局变量或局部变量。

c语言lua pushtable
(图片来源网络,侵删)

创建一个空的 Table

最基本的一步是创建一个空的 table 并将其压入栈顶。

使用函数:lua_newtable(L)

  • 参数 L: 指向 lua_State 的指针,代表当前的 Lua 上下文。
  • 返回值: 无,它会在栈顶创建一个新的、空的 table。

示例代码:

#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
int main(void) {
    lua_State *L = luaL_newstate(); // 创建 Lua 状态机
    luaL_openlibs(L);               // 打开所有标准库
    // 1. 创建一个空的 table 并压入栈顶
    // 此时栈: [ empty table ]
    lua_newtable(L);
    // ... 在这里可以向 table 中添加内容 ...
    // 2. 从栈中弹出 table,并将其赋值给一个全局变量 "my_table"
    // 此时栈: [ ]
    lua_setglobal(L, "my_table");
    lua_close(L); // 关闭 Lua 状态机
    return 0;
}

向 Table 中添加键值对

创建 table 后,你需要向其中添加数据,这个过程遵循一个固定的模式:

c语言lua pushtable
(图片来源网络,侵删)

[key] -> [value] -> [table] -> lua_settable(L, -3)

分解步骤如下:

  1. 将 Key 压入栈顶
  2. 将 Value 压入栈顶,此时栈顶是 value,下面是 key。
  3. 确保 table 也在栈中,通常它在 value 的下面。
  4. 调用 lua_settable(L, index),这个函数会从栈中弹出 key 和 value,然后找到 index 位置的 table,将 key = value 这个对设置进去,最后弹出 table。

lua_settableindex 参数是 负数,表示从栈顶向下数的位置。-1 是栈顶,-2 是栈顶下一个,-3 是再下一个。

典型的调用是 lua_settable(L, -3),因为它会弹出栈顶的 value (-1) 和 key (-2),然后对它们下面的 table (-3) 进行操作。

c语言lua pushtable
(图片来源网络,侵删)

完整示例:创建一个复杂的 Table

让我们创建一个如下的 Lua table:

my_complex_table = {
    name = "Lua C API",
    version = 5.4,
    is_enabled = true,
    authors = { "Ricardo", "Roberto" },
    config = {
        debug = true,
        max_users = 100
    }
}

对应的 C 代码如下:

#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
#include <stdio.h>
int main(void) {
    lua_State *L = luaL_newstate();
    luaL_openlibs(L);
    // 1. 创建主 table
    // 栈: [ main_table ]
    lua_newtable(L);
    // --- 添加 name = "Lua C API" ---
    // 栈: [ main_table, "name", "Lua C API" ]
    lua_pushstring(L, "name");
    lua_pushstring(L, "Lua C API");
    // 栈: [ main_table, "name", "Lua C API" ] -> 弹出 "name" 和 "Lua C API",设置到 main_table
    lua_settable(L, -3);
    // --- 添加 version = 5.4 ---
    // 栈: [ main_table, "version", 5.4 ]
    lua_pushstring(L, "version");
    lua_pushnumber(L, 5.4);
    // 栈: [ main_table, "version", 5.4 ] -> 弹出 "version" 和 5.4,设置到 main_table
    lua_settable(L, -3);
    // --- 添加 is_enabled = true ---
    // 栈: [ main_table, "is_enabled", true ]
    lua_pushstring(L, "is_enabled");
    lua_pushboolean(L, 1); // 1 代表 true, 0 代表 false
    // 栈: [ main_table, "is_enabled", true ] -> 弹出 "is_enabled" 和 true,设置到 main_table
    lua_settable(L, -3);
    // --- 添加 authors = { "Ricardo", "Roberto" } ---
    // 2.1 创建 authors 子 table
    // 栈: [ main_table, "authors", authors_table ]
    lua_pushstring(L, "authors");
    lua_newtable(L); // 创建 authors_table 并压入
    // 栈: [ main_table, "authors", authors_table ]
    // 2.2 向 authors_table 中添加元素
    // 栈: [ main_table, "authors", authors_table, "Ricardo" ]
    lua_pushstring(L, "Ricardo");
    lua_rawseti(L, -2, 1); // 更高效的方式,见下文
    // 栈: [ main_table, "authors", authors_table, "Roberto" ]
    lua_pushstring(L, "Roberto");
    lua_rawseti(L, -2, 2); // 更高效的方式,见下文
    // 栈: [ main_table, "authors", authors_table ]
    // authors_table 已经填充完毕
    // 2.3 将 authors_table 设置到 main_table
    // 栈: [ main_table, "authors", authors_table ] -> 弹出 "authors" 和 authors_table,设置到 main_table
    lua_settable(L, -3);
    // 栈: [ main_table ]
    // --- 添加 config = { ... } ---
    // 3.1 创建 config 子 table
    // 栈: [ main_table, "config", config_table ]
    lua_pushstring(L, "config");
    lua_newtable(L);
    // 栈: [ main_table, "config", config_table ]
    // 3.2 向 config_table 中添加元素
    // 栈: [ main_table, "config", config_table, "debug", true ]
    lua_pushstring(L, "debug");
    lua_pushboolean(L, 1);
    lua_settable(L, -3); // 对 config_table 操作,index 是 -3
    // 栈: [ main_table, "config", config_table, "max_users", 100 ]
    lua_pushstring(L, "max_users");
    lua_pushinteger(L, 100);
    lua_settable(L, -3); // 对 config_table 操作,index 是 -3
    // 栈: [ main_table, "config", config_table ]
    // 3.3 将 config_table 设置到 main_table
    lua_settable(L, -3);
    // 栈: [ main_table ]
    // 4. 将最终完成的 table 赋给全局变量 "my_complex_table"
    lua_setglobal(L, "my_complex_table");
    // 5. 验证一下:从 Lua 中读取并打印
    if (luaL_dostring(L, "print(my_complex_table.name)") != 0) {
        fprintf(stderr, "Error: %s\n", lua_tostring(L, -1));
    }
    lua_close(L);
    return 0;
}

编译和运行: 你需要安装 Lua 开发库,以 Ubuntu 为例,sudo apt-get install liblua5.4-dev。 然后编译:gcc -o my_app my_app.c -llua5.4 运行:./my_app 输出:Lua C API


更高效的方法:lua_rawsetilua_pushinteger

当你的 table 的 key 是连续的整数(即数组部分)时,使用 lua_settable 会稍显繁琐,C API 提供了更直接的函数 lua_rawseti

lua_rawseti(L, index, i) 的作用是:将栈顶的值赋给 table 在 index 位置的整数键 i

模式:[value] -> [table] -> lua_rawseti(L, -2, i)

  1. 将 value 压入栈。
  2. 确保 table 在栈中(通常在 value 下面)。
  3. 调用 lua_rawseti(L, -2, i),它会弹出 value,并将其赋给 table[i]

示例:创建数组 authors = { "Ricardo", "Roberto" }

// 创建主 table
lua_newtable(L); // 栈: [ main_table ]
// 创建 authors 子 table
lua_newtable(L); // 栈: [ main_table, authors_table ]
// 添加 "Ricardo"
lua_pushstring(L, "Ricardo"); // 栈: [ main_table, authors_table, "Ricardo" ]
lua_rawseti(L, -2, 1);        // 弹出 "Ricardo",赋给 authors_table[1]
                             // 栈: [ main_table, authors_table ]
// 添加 "Roberto"
lua_pushstring(L, "Roberto"); // 栈: [ main_table, authors_table, "Roberto" ]
lua_rawseti(L, -2, 2);        // 弹出 "Roberto",赋给 authors_table[2]
                             // 栈: [ main_table, authors_table ]
// 将 authors_table 设置回 main_table
lua_setfield(L, -2, "authors"); // 另一个便利函数,见下文
// 栈: [ main_table ]

便利函数:lua_setfieldlua_getfield

为了简化 "key -> value -> table -> settable" 这个三步操作,C API 提供了便利函数。

lua_setfield(L, index, key)

它执行以下操作:

  1. 从栈顶弹出一个 value。
  2. index 位置的 table 中,将 key 对应的值设为这个 value。

模式:[value] -> [table] -> lua_setfield(L, -2, "my_key")

这比下面这段代码更简洁:

// 旧方式
// lua_pushstring(L, "my_key");
// lua_pushvalue(L, -2); // 复制 value 到栈顶
// lua_settable(L, -3);
// 新方式
lua_pushstring(L, "my_value");
lua_setfield(L, -2, "my_key"); // 假设 table 在栈顶 (-1),index 是 -2

lua_getfield(L, index, key)

相反,这个函数会根据 key 从 table 中获取 value 并压入栈顶。

  1. index 位置的 table 中,查找 key 对应的 value。
  2. 将找到的 value 压入栈顶。

总结与最佳实践

任务 推荐函数 栈操作模式 说明
创建空表 lua_newtable(L) [ table ] 在栈顶创建一个新表。
添加键值对 (通用) lua_settable(L, -3) [ table, key, value ] -> [ table ] 标准方法,适用于任意类型的 key。
添加键值对 (字符串键) lua_setfield(L, -2, key) [ table, value ] -> [ table ] 更简洁,自动处理字符串 key。
设置数组元素 (整数键) lua_rawseti(L, -2, i) [ table, value ] -> [ table ] 最高效,直接设置 table[i] = value
获取值 (通用) lua_gettable(L, -2) [ table, key ] -> [ value ] 标准方法。
获取值 (字符串键) lua_getfield(L, -2, key) [ table ] -> [ value ] 更简洁,自动处理字符串 key。
获取数组元素 lua_rawgeti(L, -2, i) [ table ] -> [ value ] 直接获取 table[i]

核心流程回顾:

  1. lua_newtable(L): 创建你的主 table,现在它在栈顶。
  2. 循环添加数据:
    • 对于字符串键:lua_pushstring(L, "value"); lua_setfield(L, -2, "key");
    • 对于整数键:lua_pushstring(L, "value"); lua_rawseti(L, -2, 1);
    • 对于嵌套 table: 先用 lua_newtable(L) 创建子表,然后填充子表,最后用 lua_setfield(L, -2, "subtable_key") 把它放回父表。
  3. lua_setglobal(L, "var_name"): 当 table 构建完成后,从栈中弹出它,并将其赋给一个全局变量。

掌握这个模式后,你就可以在 C 和 Lua 之间自如地传递复杂的数据结构了。

-- 展开阅读全文 --
头像
织梦如何一键设置自定义tag标签?
« 上一篇 昨天
手机端域名如何绑定到m文件夹?
下一篇 » 昨天

相关文章

取消
微信二维码
支付宝二维码

目录[+]