当前位置:  开发笔记 > 编程语言 > 正文

通过C++中的Lua表迭代?

如何解决《通过C++中的Lua表迭代?》经验,为你挑选了1个好方法。

我正在尝试将表从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*,我正在初始化它并解析文件没问题.

编辑: 为了回应Jesse Beder的回答,我尝试使用记录器编写此代码,但我仍然无法使其工作.

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后存活下来.

编辑3: 我现在把它缩小了一点.我正在使用hge作为我的2D引擎.我把所有以前的代码都放在了函数测试中:

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

据我所知,hge对lua没有任何作用. 这是我做的一个小测试的源代码.hge 1.81的来源就在这里.

编辑4: 问题规模失控但无法帮助.这是我能够将其减少到的最小代码.

extern "C"
{
    #include 
    #include 
    #include 
}
#include 

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

Jesse Beder.. 28

调用时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"

所以你想要读取值(at -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);

根据您的第二次修改进行修改

因为当你删除外部东西时它会起作用,但是当你重新添加它时它不会起作用,我最好的猜测是你以某种方式破坏了堆栈(无论是C++堆栈还是lua堆栈).看看真正仔细的指针,尤其是当你操纵LUA状态.



1> Jesse Beder..:

调用时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"

所以你想要读取值(at -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);

根据您的第二次修改进行修改

因为当你删除外部东西时它会起作用,但是当你重新添加它时它不会起作用,我最好的猜测是你以某种方式破坏了堆栈(无论是C++堆栈还是lua堆栈).看看真正仔细的指针,尤其是当你操纵LUA状态.

推荐阅读
php
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有