我正在尝试将表从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 );
然后我尝试了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 );
最后这个:
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后继续存在。
EDIT3: 我现在已经把它缩小了一点。我正在使用hge作为我的2D引擎。 我把所有以前的代码都放在了函数测试中:
test(); //works
if( hge->System_Initiate() )
{
test(); //fails
hge->System_Start();
}
据我所知,hge对lua没有任何作用。 Here是我做的一个小测试的源代码。 hge 1.81的来源是here。
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;
}
答案 0 :(得分: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"
所以你想要读取值(在-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 :(得分:1)
阅读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)
}
希望它有所帮助。
答案 2 :(得分:0)
为什么你在参考手册的版本末尾做额外的lua_pop(L, 1)
?我可以看到这可能是一个问题,因为你超出了堆栈深度。