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

时间:2016-06-16 08:56:46

标签: lua-5.1 lua-c++-connection

我需要在Lua 5.1 C-API中创建这样的构造,而不是Lua 5.2及以上版本

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

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

预期结果:好

感谢您的回答!

1 个答案:

答案 0 :(得分:4)

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

让我们从创建表并将其分配给全局变量a开始:

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

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

lua_newtable()的文档告诉我们该函数将新表推送到Lua堆栈的顶部。这非常适合lua_setglobal(),它从堆栈顶部弹出一个值并将其分配给给定名称的全局变量。因此,在堆栈效果方面,两个功能组合(如上面的代码段中)都是平衡。堆栈平衡代码片段的优点在于您可以将它们插入任何位置,并且组合代码仍然有效。 (一般规则是:您可以用一系列语句替换单个语句,反之亦然,只要(组合)堆栈效果相同。)例如:

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

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

我们希望使用键"b"和另一个表作为值向表中添加字段。执行此操作的Lua C API函数是lua_settable()(还有其他便利函数仅适用于某些键类型,例如lua_setfield(),但我们将在此处使用lua_settable()) 。 lua_settable()需要表将键/值对存储在Lua堆栈的 somewhere 中(这通常意味着您必须将堆栈索引作为参数传递),以及作为堆栈中两个最顶层元素的键和值。密钥和值(但不是表格)将由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指的是位于关键"b"(位于-2)下方且位于另一个桌子下方的表格(位于-1的堆栈顶部)

您可能已经看到了这种情况:现在我们要修改新表,因此我们在正确的位置添加堆栈平衡代码(在将新表推入堆栈之后)。我将跳过几个步骤,并通过缩进指示我在哪里插入代码:

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())是什么期望。 Here就是我用来做的。