从C语言返回一个多维数组给Lua

3

我的问题与这个问题相似: 如何使用C API创建嵌套的Lua表

我觉得我理解了那个答案,但我仍然遇到问题。

我有一个对象数组,我正在尝试返回它们。

        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块中。当它第一次执行这个settable时,它就会退出并跳转到我的catch块。我认为我已经某种方式破坏了堆栈,但我没有看到它。
感谢@Omri Barel提供的出色答案。但我仍然不清楚在内部'for'循环之后该怎么做。
现在我有了这个: 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++ )
        {
            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的帮助。以下是我最终得出的代码片段。

        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);
        }

1
当设置x[i]=y时,其中i是一个数字,我建议您使用lua_rawseti而不是先使用lua_pushnumber再跟着使用lua_settable - undefined
1个回答

6
问题在于您在将键/值对添加到表中之前推送了太多的键/值对。您应该一次添加一个键/值对。
在调试Lua时,最好经常转储堆栈内容以检查发生了什么。 "{{link1:Programming In Lua}}"(第一版已足够)中有一些“堆栈转储”代码。
让我们看看您的代码(在框架循环内部)。
  1. 你创建了一个表格,堆栈如下:
  2. ... [table]

  3. 你推入键值对:
  4. ... [table] [key] [value] [key] [value] [key] [value] [key] [value]

  5. 你使用了 iDepth 调用了 settable,但是我觉得这不对。在这种情况下,iDepth = -(1+nItems) = -5。但是你正在推入键值对,所以应该是两倍。即使 iDepth 正确,你仍然只调用了一次,因此它只从堆栈中删除了一对键值对:
  6. ... [table] [key] [value] [key] [value] [key] [value]

  7. 你使用了 -3 调用了 settable,但 -3 是一个值,所以你会得到一个错误。

你应该在每个键值对后调用 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。我现在已经成功了,没有你的帮助我无法完成。我将在上方发布我的最终代码。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接