Итерирование через таблицу Lua из C ++?

Я пытаюсь загрузить таблицы из 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: Я попытался скопировать точный код в новый проект, пропустив все окружающие classы и прочее, о котором я не думал включать здесь и там, он работает. Но здесь этого нет, и он просто выдержит один вызов lua_next.

Edit3: Я сузил его немного дальше. Я использую hge как свой 2D-движок. Я поместил весь предыдущий код в тест функции:

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

Насколько я понимаю, hge ничего не делает с lua. Вот исходный код для небольшого теста, который я сделал. Здесь источник hge 1.81.

Edit4: размер вопроса выходит из-под контроля, но ему ничего не поделаешь . Это самый маленький код, с которым я смог его уменьшить.

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

    Когда вы вызываете lua_next , второй аргумент должен быть индексом таблицы. Поскольку вы просто нажимаете стол в стек с помощью

     lua_getglobal(L, "level"); 

    после этого вызов вашего стека будет выглядеть

     -1: таблица "уровень"
    

    (не +1 , так как стек читается вниз). Затем вы звоните

     lua_pushnil(L); 

    поэтому ваш стек будет

     -1: ключ (ноль)
     -2: таблица "уровень"
    

    Ваш стол равен -2 , поэтому, когда вы вызываете lua_next , вы должны использовать индекс -2 . Наконец, после каждой итерации ваш стек должен выглядеть так:

     -1: значение
     -2: ключ
     -3: таблица "уровень"
    

    Таким образом, вы хотите прочитать значение (в -1 ), а затем lua_next его (так что просто lua_next один раз), а затем вызовите 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 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) } 

    Надеюсь, поможет.

    Почему вы делаете дополнительный lua_pop(L, 1) в конце версии из справочного руководства? Я вижу, как это может быть проблемой, поскольку вы выходите за пределы глубины стека.

    Interesting Posts

    Как получить первый день текущей недели и месяца?

    Как указать область действия API Google для получения дня рождения

    Эффективная группа DataTable

    Предел CUDA, по-видимому, достигнут, но какой предел?

    Не удалось установить Windows XP: появляется сообщение «Голубой экран» перед «Запуск установки Windows»

    Когда используется ключевое слово C # ref всегда хорошая идея?

    Windows 8.1 переводит жесткий диск в спящий режим

    Как скачать каталог или файлы с командной строкой на сервере Linux

    Метод расширения для enums, а не экземпляр enums

    две разные библиотеки DLL с одинаковым пространством имен

    Почему нет подключенного диска, доступного под расширенным приглашением cmd, но находится под обычной подсказкой cmd?

    Вычислите смежные пропорции

    Использование: – (двоеточие в столбце) в bash

    Почему регулярные выражения имеют экспоненциальное время работы?

    Каковы параметры Xms и Xmx при запуске JVM?

    Давайте будем гением компьютера.