【问题标题】:Returning a multidimensional array from C to Lua将多维数组从 C 返回到 Lua
【发布时间】:2012-12-08 10:04:47
【问题描述】:

诚然,我的问题与此类似: How to create nested Lua tables using the C API

我以为我理解了那个答案,但我仍然有问题。

我有一个我想要返回的对象数组。

        const char * pushlist[] = {
              "status", "cmdsequence", "timestamp", "gain",
        };
        int nItems = sizeof(pushlist) / sizeof(char *);
        int iDepth = -(1 + nItems);

        // //
        // What we want to do is essentially push an array of tables.
        // The tables have keys (see pushlist above) and values.
        // The array is indexed by integers from 1 through N.
        //
        lua_newtable( L );
        for( Json::Value::UInt i = 0; i != totFrames; i++ )
        {
            lua_pushnumber( L, i + 1 );  // push the array index
            lua_newtable( L );

            Json::Value frame = params["frameinfo"][i];

            // now push the table which will be at array index (i + 1)
            for( int n = 0; n < nItems; n++ )
            {
                lua_pushstring( L, pushlist[n] );                 // push key
                lua_pushnumber( L, frame[pushlist[n]].asUInt() ); // push value
            }
            lua_settable(L, iDepth);
            lua_settable(L, -3);    // (note 1) error here
        }
        lua_settable(L, iDepth);    // (note 2) not clear on the need for this
        lua_settable(L, -3);
        lua_setglobal( L, "framedata" );

所以我想在 Lua 中看到:
[0] = {["status"] = 1, ["cmdsequence"] = 2, ["timestamp"] = 3, ["gain"] = 4}
...
[totFrames-1] = {["status"] = 5, ["cmdsequence"] = 6, ["timestamp"] = 7, ["gain"] = 8}

我不清楚注释 2 中 2 个 lua_settable 的用途,但我在上面链接到的答案表明它们是必需的。

lua_settable(L, -3)(注 1)出错。我在 C++ 中执行此操作,因此我将该代码括在 try/catch 中。当它第一次击中那个可设置的位置时,它会跳出并接住我。我在想我已经以某种方式损坏了堆栈,但我没有看到它。


感谢@Omri Barel 的出色回答。我仍然不清楚内部“for”循环之后要做什么。

我现在有这个: 常量字符 * pushlist[] = { “状态”,“cmdsequence”,“时间戳”,“增益”, }; int nItems = sizeof(pushlist) / sizeof(char *);

        // //
        // What we want to do is essentially push an array of tables.
        // The tables have keys (see pushlist above) and values.
        // The array is indexed by integers from 1 through N.
        //
        lua_newtable( L );
        for( Json::Value::UInt i = 0; i != totFrames; i++ )
        {
            lua_pushnumber( L, i + 1 );  // push the array index
            lua_newtable( L );

            Json::Value frame = params["frameinfo"][i];

            // now push the table which will be at array index (i + 1)
            for( int n = 0; n < nItems; n++ )
            {
                lua_pushnumber( L, frame[pushlist[n]].asDouble() ); // push value
                lua_setfield(L, -2, pushlist[n] );
            }
            lua_settable(L, -3);    // (note 1) error here
        }
        //lua_settable(L, -3);       <<-- not certain that this is required
        lua_setglobal( L, "framedata" );

我不再爆炸,但我的 Lua 失败(没有错误消息,它只是退出)。我怀疑我没有损坏堆栈,但不知何故我没有正确完成这个表,所以我的返回很混乱。

我在这个数组之前将其他几个返回值压入 Lua 堆栈,然后再压入一个。

我的 Lua 调用是这样的:

       param1,param2,framedata,Err = CCall.ReadFromC( arg, arg );

我终于有这个工作了。它需要进一步测试,但到目前为止似乎是正确的。再次感谢@Omri Barel。这是我最终得到的代码 sn-p。

        const char * pushlist[] = {
              "status", "cmdsequence", "timestamp", "gain",
        };
        int nItems = sizeof(pushlist) / sizeof(char *);

        // //
        // What we want to do is essentially push an array of tables.
        // The tables have keys (see pushlist above) and values.
        // The array is indexed by integers from 1 through N.
        //
        lua_newtable( L );
        for( Json::Value::UInt i = 0; i != totFrames; i++ )
        {
            Json::Value frame = params["frameinfo"][i];

            // now push the table which will be at array index (i + 1)
            lua_newtable( L );
            for( int n = 0; n < nItems; n++ )
            {
                const char * itemName = pushlist[n];
                if( frame[itemName].isNull() ) continue;
                lua_pushnumber( L, frame[pushlist[n]].asDouble() ); // push value
                lua_setfield(L, -2, pushlist[n] );
            }
            lua_rawseti(L, -2, i + 1);
        }

【问题讨论】:

  • x[i]=y设置i为数字时,我建议你使用lua_rawseti而不是lua_pushnumber后跟lua_settable

标签: c++ lua


【解决方案1】:

问题是您在将它们添加到表之前推送了太多的键/值对。您应该一次添加一对。

在调试 Lua 时,您能做的最好的事情就是经常转储堆栈的内容,以检查发生了什么。 “Programming In Lua”中有一些“堆栈转储”代码(第一版已经足够了)。

让我们看看您的代码(在框架循环内)。

  1. 您创建一个表。堆栈是:

    ...[表格]

  2. 你推送成对的键/值:

    ... [table] [key] [value] [key] [value] [key] [value] [key] [value]

  3. 你用iDepth 调用settable,这对我来说看起来不对。在这种情况下iDepth = -(1+nItems) = -5。但是你在推动对子,所以应该是双倍。但即使iDepth 是对的,您仍然只调用了一次,因此它只会从堆栈中删除一对:

    ... [表] [键] [值] [键] [值] [键] [值]

  4. 你用 -3 调用 settable,但是 -3 是 [value] 所以你得到一个错误。

您应该在每个键/值对之后调用 settable(带 -3)。

我还建议使用更清晰的setfield。而不是:

lua_pushstring(L, key);
lua_pushnumber(L, value);
lua_settable(L, -3);

你可以使用:

lua_pushnumber(L, value);
lua_setfield(L, -2, "key");

【讨论】:

  • 再次感谢@Omri Barel。我现在有这个工作,没有你我做不到。我将在上面发布我的最终代码。
  • @halm 很高兴我能帮上忙 ;-)
猜你喜欢
  • 2013-12-09
  • 1970-01-01
  • 2014-07-23
  • 1970-01-01
  • 2012-05-04
  • 2019-03-17
  • 2018-01-05
  • 2015-05-30
  • 1970-01-01
相关资源
最近更新 更多