通过从C ++一个Lua表迭代?(Iterating through a Lua table fro

2019-07-18 08:31发布

我试图加载从表中的Lua到C ++,但我无法得到它的权利。 我通过第一次迭代得很好,但随后在第二次调用lua_next崩溃得到。 有任何想法吗?

Lua的文件:

level = { 1, 2, 3, }

C ++文件 - 首先,我这样做:

lua_getglobal( L, "level" );
for( lua_pushnil( L ); lua_next( L, 1 ); lua_pop( L, -2 ) )
{
    if( lua_isnumber( L, -1 ) ) {
        int i = (int)lua_tonumber( L, -1 );
        //use number
    }
}
lua_pop( L, 1 );

然后我从试图参考手册 :

lua_getglobal( L, "level" );
int t = 1;
lua_pushnil( L );
while( lua_next( L, t ) ) {
    printf( "%s - %s", 
        lua_typename( L, lua_type( L, -2 ) ),
        lua_typename( L, lua_type( L, -1 ) ) );
    lua_pop( L, 1 );
}
lua_pop( L, 1 );

最后这一点:

lua_getglobal( L, "level" );
lua_pushnil( L );

lua_next( L, 1 );
if( lua_isnumber( L, -1 ) ) {
    int i = (int)lua_tonumber( L, -1 );
    //use number fine
}
lua_pop( L, 1 );

lua_next( L, 1 ); //crashes

etc...

当然L是lua_State *和我初始化它和解析该文件还行。

编辑:在回答杰西·贝德尔答案我想这个代码,用记录仪,但我仍然无法得到它的工作。

Log::Get().Write( "engine", "stack size: %i", lua_gettop( L ) );

lua_getglobal(L, "level");
if( lua_istable( L, -1 ) )
    Log::Get().Write( "engine", "-1 is a table" );

lua_pushnil(L);
if( lua_isnil( L, -1 ) )
    Log::Get().Write( "engine", "-1 is now nil" );
if( lua_istable( L, -2 ) )
    Log::Get().Write( "engine", "-2 is now table" );

int pred = lua_next( L, -2 );
Log::Get().Write( "engine", "pred: %i", pred );
while( pred ) {
    Log::Get().Write( "engine", "loop stuff" );
    if( lua_isnumber( L, -1 ) ) {
        int i = (int)lua_tonumber( L, -1 );
        //use number
        Log::Get().Write( "engine", "num: %i", i );
    }
    Log::Get().Write( "engine", "stack size: %i", lua_gettop( L ) );
    if( lua_istable( L, -3 ) )
        Log::Get().Write( "engine", "-3 is now table" );

    lua_pop( L, 1 );
    Log::Get().Write( "engine", "stack size: %i", lua_gettop( L ) );
    if( lua_istable( L, -2 ) )
        Log::Get().Write( "engine", "-2 is now table" );

    pred = lua_next( L, -2 );
    Log::Get().Write( "engine", "pred: %i", pred );
}
lua_pop( L, 1 );

这给了这样的输出:

stack size: 0
-1 is a table
-1 is now nil
-2 is now table
pred: 1
loop stuff
num: 1
stack size: 3
-3 is now table
stack size: 2
-2 is now table

一切你说,杰西,似乎是正确的。 但它仍然不能进入下一个迭代。

EDIT2:我想确切的代码复制到一个新的项目,跳过所有周围的类和东西我也懒得在这里和那里它的作品包括。 但这里没有,而且它只是一个生存的通话lua_next。

EDIT3:我现在进一步缩小下来一点。 我用HGE作为我的2D引擎。 我把在功能测试中所有以前的代码:

test(); //works
if( hge->System_Initiate() )
{       
    test(); //fails
    hge->System_Start();
}

据我了解HGE不会做任何事情卢阿。 这里的一个小测试,我做的源代码。 为HGE 1.81的来源是这里 。

Edit4:问题规模失控,但也没有办法。 这是最小的代码,我已经能够将其降低到。

extern "C"
{
    #include <lua/lua.h>
    #include <lua/lualib.h>
    #include <lua/lauxlib.h>
}
#include <hge\hge.h>

bool frame_func()
{   
    return true;
}

bool render_func()
{
    return false;
}

void test()
{
    lua_State *L = lua_open();
    luaL_openlibs( L );

    if( luaL_dofile( L, "levels.lua" ) ) {
        lua_pop( L, -1 );
        return;
    }
    lua_getglobal(L, "level");
    lua_pushnil(L);

    while( lua_next( L, -2 ) ) {
        if( lua_isnumber( L, -1 ) ) {
            int i = (int)lua_tonumber( L, -1 );
            //use number
        }
        lua_pop( L, 1 );
    }
    lua_pop( L, 1 );

    lua_close( L );
}

int main()
{
    HGE *hge = hgeCreate( HGE_VERSION );

    hge->System_SetState( HGE_FRAMEFUNC, frame_func );
    hge->System_SetState( HGE_RENDERFUNC, render_func );
    hge->System_SetState( HGE_WINDOWED, true );
    hge->System_SetState( HGE_SCREENWIDTH, 800 );
    hge->System_SetState( HGE_SCREENHEIGHT, 600 );
    hge->System_SetState( HGE_SCREENBPP, 32 );

    //test(); //works

    if( hge->System_Initiate() )
    {       
        test(); //fails
        hge->System_Start();
    }

    hge->Release();

    return 0;
}

Answer 1:

当你调用lua_next ,第二个参数应该是表的索引。 既然你只需按下表到堆栈

lua_getglobal(L, "level");

之后打电话给你叠的样子

-1: table "level"

(不+1 ,因为堆栈读下去)。 然后调用

lua_pushnil(L);

所以你的筹码会

-1: key (nil)
-2: table "level"

你的表是-2 ,所以当你打电话lua_next ,你应该使用索引-2 。 最后,在每次迭代之后,你的筹码应该是这样的:

-1: value
-2: key
-3: table "level"

所以,你想读的值( -1 ),然后弹出它(所以只是弹出一次),然后调用lua_next获取下一个关键。 所以,这样的事情应该工作:

lua_getglobal(L, "level");
lua_pushnil(L);

while(lua_next(L, -2)) {  // <== here is your mistake
    if(lua_isnumber(L, -1)) {
        int i = (int)lua_tonumber(L, -1);
        //use number
    }
    lua_pop(L, 1);
}
lua_pop(L, 1);

Edit(编辑)根据您的第二个编辑

因为当你删除外部的东西它的工作原理,但是当你将它添加回来没有,我最好的猜测是,你在某种程度上破坏堆栈(不管是C ++堆栈或LUA堆栈)。 真的仔细看看你的指针,尤其是当你操纵LUA状态。



Answer 2:

阅读LUA手动lua_next你会发现可能出现的使用lua_tostring直接的一个关键问题,那就是你必须检查的关键价值,然后决定使用lua_tostring或lua_tonumber。 所以,你可以试试下面的代码:

   std::string key
   while(lua_next(L, -2) != 0){ // in your case index may not be -2, check

    // uses 'key' (at index -2) and 'value' (at index -1)

    if (lua_type(L, -2)==LUA_TSTRING){ // check if key is a string
         // you may use key.assign(lua_tostring(L,-2));
    }
    else if (lua_type(L, -2)==LUA_TNUMBER){ //or if it is a number
         // this is likely to be your case since you table level = { 1, 2, 3, }
         // don't declare field ID's
         // try:
         // sprintf(buf,"%g",lua_tonumber(L,-2));
         // key.assign(buf);
    }
    else{
        // do some other stuff
    }
    key.clear();
    lua_pop(L,1)
   }

希望能帮助到你。



Answer 3:

你为什么这样做额外的lua_pop(L, 1)在距离参考手册版本结束了吗? 我可以看到这可能是一个问题,因为你无法弹出堆栈深度。



文章来源: Iterating through a Lua table from C++?