1 (2014-03-22 04:23:49 отредактировано Delv)

Тема: Lua и С++, ошибка

Здравствуйте!
Внутри подключаемой из Lua dll есть вот такая функция на C:

static int forLua_OnQuote(lua_State *L)
{
    const char *argClass = NULL;
        size_t argClassLen = 0;

    const char *argSec = NULL;  
        size_t argSecLen = 0;
    
    argClass = luaL_checklstring(L, 1, &argClassLen);
    argSec = luaL_checklstring(L, 2, &argSecLen);

    stack ss;

    if( strcmp(argClass,"SPBFUT")==0 && strcmp(argSec,"RIM4")==0)
    {
        lua_settop(L,0);
        lua_getfield (L, LUA_GLOBALSINDEX, "getQuoteLevel2");
        lua_pushstring (L, argClass);
                lua_pushstring (L, argSec);

        int r = lua_pcall (L, 2 /* num args */, 1 /* num res */, 0);
                if (r==0)
                {
                                //успешный вызов, в стеке таблица
                    size_t argLeng = 0; 
                byte cc=0;

                lua_pushnil(L);
                while (lua_next(L, -2) != 0)
                {
                    std::string k1 = luaL_checklstring(L, -2, &argLeng); // здесь лежит ключ (bid_count, offer_count, bid, offer)

                    switch (cc) {

                    case 0: ss.bid_count   = atoi( ((std::string)luaL_checklstring(L, -1, &argLeng)).c_str() ); break;
                    case 1: ss.offer_count = atoi( ((std::string)luaL_checklstring(L, -1, &argLeng)).c_str() ); break;
                    case 2: // здесь идет обработка вложенной таблицы bid
                            lua_pushnil(L);
                            while (lua_next(L, -2) != 0) //!!!!!!! при второй итерации здесь возникает ошибка:
                            {                            //!!!!!!! lua invalid key to 'next' 
                                 
                                 std::string k2 = luaL_checklstring(L, -2, &argLeng); // здесь лежит ключ, по -1 лежит значение

                                 lua_pop(L, 1);
                            }
                            lua_pop(L, 1);
                            break;
                    case 3: // здесь должна быть обработка вложенной таблицы offer
                            break;
                    }

                    lua_pop(L, 1);
                    cc++;
                }
                lua_pop(L, 1);
        }
        else
        {
            //какая-то ошибка при вызове getQuoteLevel2
            MsgToQuik(L, (char *)lua_tostring (L, -1));
        }
    }

    return(1);
}

В Lua она регистрируется как коллбэк OnQuote. При попытке пройтись по массиву bid на второй итерации возникает ошибка(lua invalid key to 'next'), хотя первую пару ключ/значение цикл видит верно. Ключ: "1", значение: "таблица". Если погрузиться ниже, в bid[1], то видит оба ключа и оба значения. Если не погружаться во вложенные таблицы, а пройтись только по первой, в которой всего 4 значения, то тоже все хорошо. В чем я тут неправ, откуда ошибка? Подскажите пожалуйста.

2

Re: Lua и С++, ошибка

Я не проверял у себя ваш код, но на сколько помню, ошибка вот в чем.
Вот здесь вы обращаетесь по относительному индексу с конца
while (lua_next(L, -2) != 0)

но вот здесь у вас на самом деле происходит изменение стека
lua_pop(L, 1);

и индекс -2 - уже не подходит.

Вот в этом проектике здесь я с подобной бедой сталкивался
http://quik2dde.ru/viewtopic.php?id=61
и, помнится, просто перешел на положительный индекс, где уже постоянно и на самом деле лежит итерируемая таблица.

Думать как надо вам поменять код мне сейчас лень, посмотрите исходники по приведённой ссылке.
Если получится - напишите что поправили.
Если не получится понять - тоже напишите, тогда уже буду мозг напрягать, вспоминать )

3

Re: Lua и С++, ошибка

переписал блок с использованием положительных индексов:

 lua_pushnil(L);
 while (lua_next(L, 1) != 0) // этот цикл выполняется 4 раза, по кол-ву элементов
 {                                        // поля идут в порядке списка из документации по getQuoteLevel2
                
     std::string hh = luaL_checklstring(L, 2, &argLen); // здесь лежит ключ

     switch (cc) {

       case 0: ss.bid_count   = atoi( ((std::string)luaL_checklstring(L, 3, &argLen)).c_str() ); break;
       case 1: ss.offer_count = atoi( ((std::string)luaL_checklstring(L, 3, &argLen)).c_str() ); break;
       case 2:
                    lua_pushnil(L);
                    while (lua_next(L, 3) != 0)
                    {
                         std::string hh = luaL_checklstring(L, 4, &argLen); // здесь лежит ключ


                         lua_pop(L,1);
                     }
                     lua_pop(L,1);
                     break;

       case 3:
                     break;
     }            

                     lua_pop(L,1);
                 cc++;
}
       lua_pop(L,1);

Расчертил на бумажке движения стека. В теории все должно быть правильно. На практике все та же ошибка на второй итерации в case 2.

4 (2014-03-22 04:24:53 отредактировано Delv)

Re: Lua и С++, ошибка

Разобрался все-таки. Адский трэш. Оказывается, все дело в том, что Lua здесь не любит ключи типа строка!
Массив, видимо, специально никто не нумеровал и ключи были созданы автоматически. А может, причина в чем-то еще.
Пришлось сделать так:

byte cc=0;
lua_pushnil(L);
while (lua_next(L, 1) != 0) // этот цикл выполняется 4 раза, по кол-ву элементов
{                           // поля идут в порядке списка из документации
     int i=0;
     hh = luaL_checklstring(L, 2, &argLen); // здесь лежит ключ
     switch (cc) 
     {
       case 0: ss.bid_count   = atoi(luaL_checklstring(L, 3, &argLen));break;
       case 1: ss.offer_count = atoi(luaL_checklstring(L, 3, &argLen));break;
       case 2: // bid
             lua_pushnil(L);
             while (lua_next(L, 3) != 0)
             {
                 i++;  
                 hh = luaL_checklstring(L, 4, &argLen); // здесь лежит ключ
                                
                         /* обработка вложенных таблиц */              

                                        //  достаем не только значение, но и ключ, 
                 lua_pop(L,2);          //  который положила в стек lua_next
                 lua_pushinteger(L,i);  //  здесь кладем в стек ключ типа integer собственноручно
              }     
              break;
        case 3: // offer
            
     }    
     lua_pop(L,1);
     cc++;
}
lua_pop(L,1);

Выравнивание стека, конечно же, изменилось, пришлось отступать от хрестоматийных вещей и все внимательно
смотреть. В коде есть комментарии.