从C ++迭代通过Lua表? [英] Iterating through a Lua table from C++?

查看:148
本文介绍了从C ++迭代通过Lua表?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我尝试从 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);
//使用数字
}
}
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);
//使用数字
}
lua_pop(L,1);

lua_next(L,1); // crashes

etc ...



自然L是一个lua_State *



编辑:
在回应Jesse Beder的回答时,我试过这个程式码

  Log :: Get()。Write(引擎,堆栈大小:%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);
//使用数字
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是表
-1现在是nil
-2现在是表
pred:1
循环东西
num:1
堆栈大小:3
-3现在是表
堆栈大小:2
-2现在是表

你说的一切,Jesse,似乎都是真的。


我试图将确切的代码复制到一个新的项目中,但是它仍然没有到下一个迭代。



< ,跳过所有周围的类和东西,我没有打扰,包括这里和那里它的工作。但是在这里它不会,它只会生存一个lua_next。



Edit3:
我缩小了下来有点进一步了。我使用 hge 作为我的2D引擎。
我把所有以前的代码放在函数test中:

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

据我所知,hge不会对lua做任何事情。
这里是我做的一个小测试的源代码。 hge 1.81的来源为此处



Edit4:
问题大小无法控制,但无法帮助。这是我能够将其减少到最小的代码。

  externC
{
#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 );
//使用数字
}
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(); // failed
hge-> System_Start();
}

hge-> Release();

return 0;
}


解决方案

$ c> lua_next ,第二个参数应该是表的索引。因为你只是将表推到堆栈上。

  lua_getglobal(L,level); 

之后调用你的堆栈看起来像

 
-1:表level

(不 +1 ,因为堆栈被读取下来)。然后你呼叫

  lua_pushnil(L); 

所以你的堆栈将是

 
-1:key(nil)
-2:表level

-2 ,因此当您调用 lua_next 时,应使用索引 -2 。最后,在每次迭代后,你的堆栈应该看起来像:

 
-1:value
-2:key
-3:表level

所以你想读取值(在 -1 )然后弹出它(所以只弹出一次),然后调用 lua_next 得到下一个键。所以这样的东西应该工作:

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

while(lua_next(L,-2)){//< ==这里是你的错误
if(lua_isnumber(L,-1)){
int i =(int)lua_tonumber(L,-1);
//使用数字
}
lua_pop(L,1);
}
lua_pop(L,1);

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

因为它在你删除外部东西时,但不是当你添加它的工作,我最好的猜测是,你以某种方式(C ++堆栈或lua堆栈)损坏堆栈。请仔细查看您的指针,特别是在操作lua状态时。


I'm trying to load tables from Lua to C++ but I'm having trouble getting it right. I'm getting through the first iteration just fine but then at the second call to lua_next it crashes. Any ideas?

Lua file:

level = { 1, 2, 3, }

C++ file - First I did this:

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

Then I tried from the reference manual:

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

And finally this:

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...

Naturally L is a lua_State* and I'm initializing it and parsing the file okay.

Edit: In response to Jesse Beder answer I tried this code, with a logger, but I still can't get it to work.

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

Which gave this output:

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

Everything you said, Jesse, seems to hold true. But it still fails to go to the next iteration.

Edit2: I tried to copy the exact code into a new project, skipping all the surrounding classes and stuff I didn't bother to include here and there it works. But here it doesn't, and it will just survive one call the lua_next.

Edit3: I've narrowed it down a bit further now. I'm using hge as my 2D engine. I put all the previous code in the function test:

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

As far as I understand hge doesn't do anything with lua. Here's the source code for a small test I made. The source for hge 1.81 is here.

Edit4: The question size is getting out of control but it can't be helped. This is the smallest code I've been able to reduce it to.

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

解决方案

When you call lua_next, the second argument should be the index of the table. Since you're just pushing the table onto the stack with

lua_getglobal(L, "level");

after that call your stack will look like

-1: table "level"

(not +1, since the stack is read going down). Then you call

lua_pushnil(L);

so your stack will be

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

Your table is at -2, so when you call lua_next, you should use the index -2. Finally, after each iteration, your stack should look like:

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

So you want to read the value (at -1) and then pop it (so just pop once), and then call lua_next to get the next key. So something like this should work:

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 based on your second edit

Since it works when you remove external stuff, but doesn't when you add it back in, my best guess is that you're corrupting the stack somehow (either the C++ stack or the lua stack). Look really carefully at your pointers, especially when you manipulate the lua state.

这篇关于从C ++迭代通过Lua表?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆