如何使用 C-API 在 Lua 5.1 中创建 table in table?

How to create table in table in Lua 5.1 using C-API?

我需要在 Lua 5.1 C-API 中创建这样的构造,而不是在 Lua 5.2 及更高版本[=15 中=]

a = {["b"] = {["c"] = {["d"] = {["e"] = "GOOD"}}}}

print(a.b.c.d.e);

预期结果:良好

感谢解答!

Lua C API 是基于堆栈的。这意味着大多数 C API 函数的行为不仅取决于给定的参数,还取决于 Lua 堆栈的内容(通常是 lua_State* 变量的一部分称为 L)。特定 API 函数在堆栈内容方面的期望以及它如何影响堆栈的元素,您必须在 Lua manual.

中查找

让我们开始创建一个 table 并将其分配给全局变量 a:

lua_newtable( L );
lua_setglobal( L, "a" );

这相当于 Lua 代码片段:a = {}.

lua_newtable() tells us that the function pushes the new table to the top of the Lua stack. That fits nicely with lua_setglobal() 的文档,它从堆栈顶部弹出一个值并将其分配给给定名称的全局变量。因此,就堆栈效应而言,这两个函数的组合(如上面的代码片段所示)是 平衡的 。堆栈平衡代码片段的好处是您可以将它们插入任何地方,并且组合后的代码仍然有效。 (一般规则是:您可以用一系列语句替换单个语句,反之亦然,只要(组合的)堆栈效果相同。)例如:

lua_newtable( L );  /* ==> stack: ..., {} */
lua_pushnil( L ); /* ==> stack: ..., {}, nil */
lua_pop( L, 1 ); /* ==> stack: ..., {} */
lua_setglobal( L, "a" ); /* ==> stack: ... */

仍会将 table 分配给全局变量 a,因为 lua_pushnil( L );lua_pop( L, 1 ); 组合不会更改 Lua 堆栈内容。我们将添加修改 table after 的代码,而不是这个无用的 pushing/popping 它被推入堆栈,并且 before 它被从堆栈中移除并分配给全局变量。正如我所说,您可以在两个 Lua C API 函数之间的任何位置插入堆栈平衡代码片段,因此您只需确定堆栈包含您需要的所有元素的正确位置。

我们想用键 "b" 和另一个 table 作为值向 table 添加一个字段。 Lua C API 函数是 lua_settable() (there are other convenience functions that work for certain key types only, e.g. lua_setfield(),但我们将在这里使用 lua_settable()lua_settable() 需要 table 将 key/value-pair 存储在 某处 的 Lua 堆栈上(这通常意味着您必须传递堆栈索引作为参数),键和值作为堆栈上的两个最顶层元素。键和值(但不是 table)都将按 lua_settable():

弹出
lua_newtable( L );  /* ==> stack: ..., {} */
lua_pushliteral( L, "b" ); /* ==> stack: ..., {}, "b" */
lua_newtable( L ); /* ==> stack: ..., {}, "b", {} */
lua_settable( L, -3 ); /* ==> stack: ..., {} */
lua_setglobal( L, "a" ); /* ==> stack: ... */

等效的 Lua 代码为 a = { b = {} }

通常您并不真正关心 Lua 堆栈的某个点下方的内容,而那是相对于堆栈顶部的索引(上面代码片段中的 -3 )参加进来。 -3 指的是 table 就在键 "b" 下方(在 -2 处)和另一个 table 下方(在堆栈处顶部 -1).

你可能已经知道这是怎么回事了:现在我们要修改新的 table,所以我们在正确的地方添加堆栈平衡代码(在新的 table 之后压入堆栈)。我将跳过几个步骤并通过缩进指示我插入代码的位置:

lua_newtable( L );  /* ==> stack: ..., {} */
{
  lua_pushliteral( L, "b" ); /* ==> stack: ..., {}, "b" */
  lua_newtable( L ); /* ==> stack: ..., {}, "b", {} */
  {
    lua_pushliteral( L, "c" ); /* == stack: ..., {}, "b", {}, "c" */
    lua_newtable( L ); /* ==> stack: ..., {}, "b", {}, "c", {} */
    {
      lua_pushliteral( L, "d" );
      lua_newtable( L );
      {
        lua_pushliteral( L, "e" );
        lua_pushliteral( L, "GOOD" );
        lua_settable( L, -3 );
      }
      lua_settable( L, -3 );
    }
    lua_settable( L, -3 ); */ ==> stack: ..., {}, "b", {} */
  }
  lua_settable( L, -3 ); /* ==> stack: ..., {} */
}
lua_setglobal( L, "a" ); /* ==> stack: ... */

当您开发具有复杂堆栈操作的代码时,在关键点打印出当前堆栈内容通常会有所帮助,或者至少检查堆栈上的元素数量(参见 lua_gettop()) is what you expect. Here 是什么我用它。