我正在尝试将表从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状态.
调用时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状态.