«Ошибка: попытка вызвать нулевое значение» при попытке вызвать сценарий lua

#c #lua

#c #lua

Вопрос:

Я пытаюсь вызвать функцию lua из C и продолжаю получать сообщение об ошибке «Ошибка: попытка вызвать нулевое значение».

Функция lua создает объект C , а затем вызывает один из его методов, код glue был сгенерирован с помощью tolua . При вызове функции lua я передаю указатель lua_State, поскольку класс C нуждается в указателе для своего конструктора, который ему передает функция lua.

Но, насколько я могу судить, это никогда не заходит так далеко, он просто вообще не запускает скрипт. По крайней мере, ошибка не ссылается ни на какие номера строк в скрипте.

Вот код C , вызывающий функцию:

 int main()
{

lua_State *lState;

lState = luaL_newstate(); //new lua state
tolua_TestClass_open (lState); //open libs for TestClass

int iStatus = luaL_loadfile( lState, "lua1.lua" ); //load script
if (iStatus)
{
    std::cout << "Error: " << lua_tostring( lState, -1 );
    return 1;
}

iStatus = lua_pcall( lState, 0, 0, 0); //initialise the lua script
if( iStatus )
{
    std::cout << "Error: " << lua_tostring( lState, -1 );
    return 1;
}

lua_getglobal( lState, "lua1Function" ); //starting the function call
lua_pushlightuserdata (lState, lState); //lState is also being passed in as a parameter

iStatus = lua_pcall( lState, 1, 0, 0 ); //calling on this lua state with 1 argument expecting 0 outputs
if( iStatus ) //error checking
{
    std::cout << "Error: " << lua_tostring( lState, -1 );
    return 1;
}

return 1;
}
  

Вот сценарий lua:

 function lua1Function(lstate)
tclass = TestClass:new();
tclass:method1();
tclass:method3();
end
  

Я почти уверен, что это не так просто, как забыть сделать:

 tclass = TestClass:new(lstate);
  

Поскольку код glue, похоже, указывает, что мне не нужно этого делать, здесь:

 /* method: new of class  TestClass */
#ifndef TOLUA_DISABLE_tolua_TestClass_TestClass_new00
static int tolua_TestClass_TestClass_new00(lua_State* tolua_S)
{
#ifndef TOLUA_RELEASE
 tolua_Error tolua_err;
 if (
     !tolua_isusertable(tolua_S,1,"TestClass",0,amp;tolua_err) ||
     !tolua_isnoobj(tolua_S,2,amp;tolua_err)
 )
  goto tolua_lerror;
 else
#endif
 {
  lua_State* tolua_var_1 =  tolua_S; //seems to know I want the lua_State by default,
//usually it will pop a usertype or luanumber or whatever off the stack,
//depending on the parameter
  {
   TestClass* tolua_ret = (TestClass*)  Mtolua_new((TestClass)(tolua_var_1));
    tolua_pushusertype(tolua_S,(void*)tolua_ret,"TestClass");
  }
 }
 return 1;
#ifndef TOLUA_RELEASE
 tolua_lerror:
 tolua_error(tolua_S,"#ferror in function 'new'.",amp;tolua_err);
 return 0;
#endif
}
#endif //#ifndef TOLUA_DISABLE
  

И сообщение об ошибке, которое выдает, похоже, подтверждает мою теорию: «ошибка в функции ‘new’. аргумент # 2 — ‘userdata’; ожидается ‘[отсутствие объекта]’.»
т. е. он не ожидал / не нуждается в том, чтобы я передавал этот указатель lua_State

Я в растерянности, у меня много проблем с поиском решений проблем с lua, потому что учебные пособия / документация, похоже, довольно скудны в том, что касается tolua , но сейчас слишком поздно менять библиотеку привязки.

Я был бы признателен за любую помощь, надеюсь, я предоставил достаточно для диагностики проблемы.

РЕДАКТИРОВАТЬ: вот мой TestClass.cpp код (вероятно, вы можете игнорировать method1, 2 и 3, поскольку они, похоже, не вызываются из-за этой ошибки):

 #include "TestClass.h"
#include <iostream>

TestClass::TestClass(lua_State *L)
{
    num = NULL;
    lState = L;
}

int TestClass::method1()
{
    int iStatus = luaL_loadfile( lState, "lua2.lua" );
    if (iStatus)
    {
        std::cout << "Error: " << lua_tostring( lState, -1 );
        return 1;
    }

    iStatus = lua_pcall( lState, 0, 0, 0); //this might be to initialise the lua script
    if( iStatus )
    {
        std::cout << "Error: " << lua_tostring( lState, -1 );
        return 1;
    }

    ///////////call lua function, passing on self pointer onto the stack////////////////

    lua_getglobal( lState, "lua2Function" );
    tolua_pushusertype(lState, this, "TestClass");

    iStatus = lua_pcall( lState, 1, 1, 0 );
    if( iStatus ) //error checking
    {
        std::cout << "Error: " << lua_tostring( lState, -1 );
        return 1;
    }

    ///////////lua function returns an int, return it////////////
    num = lua_tointeger( lState, -1 );

    return 0;
}

int TestClass::method2(int i)
{
    i  = 2;
    return i;
}

void TestClass::method3()
{
    std::cout << (char)num << std::endl;
}

/*
** Lua binding: TestClass
** Generated automatically by tolua  -1.0.92 on 04/05/11 17:59:24.
*/

#ifndef __cplusplus
#include "stdlib.h"
#endif
#include "string.h"

#include "tolua  .h"


/* function to release collected object via destructor */
#ifdef __cplusplus

static int tolua_collect_TestClass (lua_State* tolua_S)
{
 TestClass* self = (TestClass*) tolua_tousertype(tolua_S,1,0);
    Mtolua_delete(self);
    return 0;
}
#endif


/* function to register type */
static void tolua_reg_types (lua_State* tolua_S)
{
 tolua_usertype(tolua_S,"TestClass");
}

/* method: new of class  TestClass */
#ifndef TOLUA_DISABLE_tolua_TestClass_TestClass_new00
static int tolua_TestClass_TestClass_new00(lua_State* tolua_S)
{
#ifndef TOLUA_RELEASE
 tolua_Error tolua_err;
 if (
     !tolua_isusertable(tolua_S,1,"TestClass",0,amp;tolua_err) ||
     !tolua_isnoobj(tolua_S,2,amp;tolua_err)
 )
  goto tolua_lerror;
 else
#endif
 {
  lua_State* tolua_var_1 =  tolua_S;
  {
   TestClass* tolua_ret = (TestClass*)  Mtolua_new((TestClass)(tolua_var_1));
    tolua_pushusertype(tolua_S,(void*)tolua_ret,"TestClass");
  }
 }
 return 1;
#ifndef TOLUA_RELEASE
 tolua_lerror:
 tolua_error(tolua_S,"#ferror in function 'new'.",amp;tolua_err);
 return 0;
#endif
}
#endif //#ifndef TOLUA_DISABLE

/* method: new_local of class  TestClass */
#ifndef TOLUA_DISABLE_tolua_TestClass_TestClass_new00_local
static int tolua_TestClass_TestClass_new00_local(lua_State* tolua_S)
{
#ifndef TOLUA_RELEASE
 tolua_Error tolua_err;
 if (
     !tolua_isusertable(tolua_S,1,"TestClass",0,amp;tolua_err) ||
     !tolua_isnoobj(tolua_S,2,amp;tolua_err)
 )
  goto tolua_lerror;
 else
#endif
 {
  lua_State* tolua_var_1 =  tolua_S;
  {
   TestClass* tolua_ret = (TestClass*)  Mtolua_new((TestClass)(tolua_var_1));
    tolua_pushusertype(tolua_S,(void*)tolua_ret,"TestClass");
    tolua_register_gc(tolua_S,lua_gettop(tolua_S));
  }
 }
 return 1;
#ifndef TOLUA_RELEASE
 tolua_lerror:
 tolua_error(tolua_S,"#ferror in function 'new'.",amp;tolua_err);
 return 0;
#endif
}
#endif //#ifndef TOLUA_DISABLE

/* method: method1 of class  TestClass */
#ifndef TOLUA_DISABLE_tolua_TestClass_TestClass_method100
static int tolua_TestClass_TestClass_method100(lua_State* tolua_S)
{
#ifndef TOLUA_RELEASE
 tolua_Error tolua_err;
 if (
     !tolua_isusertype(tolua_S,1,"TestClass",0,amp;tolua_err) ||
     !tolua_isnoobj(tolua_S,2,amp;tolua_err)
 )
  goto tolua_lerror;
 else
#endif
 {
  TestClass* self = (TestClass*)  tolua_tousertype(tolua_S,1,0);
#ifndef TOLUA_RELEASE
  if (!self) tolua_error(tolua_S,"invalid 'self' in function 'method1'", NULL);
#endif
  {
   int tolua_ret = (int)  self->method1();
   tolua_pushnumber(tolua_S,(lua_Number)tolua_ret);
  }
 }
 return 1;
#ifndef TOLUA_RELEASE
 tolua_lerror:
 tolua_error(tolua_S,"#ferror in function 'method1'.",amp;tolua_err);
 return 0;
#endif
}
#endif //#ifndef TOLUA_DISABLE

/* method: method2 of class  TestClass */
#ifndef TOLUA_DISABLE_tolua_TestClass_TestClass_method200
static int tolua_TestClass_TestClass_method200(lua_State* tolua_S)
{
#ifndef TOLUA_RELEASE
 tolua_Error tolua_err;
 if (
     !tolua_isusertype(tolua_S,1,"TestClass",0,amp;tolua_err) ||
     !tolua_isnumber(tolua_S,2,0,amp;tolua_err) ||
     !tolua_isnoobj(tolua_S,3,amp;tolua_err)
 )
  goto tolua_lerror;
 else
#endif
 {
  TestClass* self = (TestClass*)  tolua_tousertype(tolua_S,1,0);
  int tolua_var_2 = ((int)  tolua_tonumber(tolua_S,2,0));
#ifndef TOLUA_RELEASE
  if (!self) tolua_error(tolua_S,"invalid 'self' in function 'method2'", NULL);
#endif
  {
   int tolua_ret = (int)  self->method2(tolua_var_2);
   tolua_pushnumber(tolua_S,(lua_Number)tolua_ret);
  }
 }
 return 1;
#ifndef TOLUA_RELEASE
 tolua_lerror:
 tolua_error(tolua_S,"#ferror in function 'method2'.",amp;tolua_err);
 return 0;
#endif
}
#endif //#ifndef TOLUA_DISABLE

/* method: method3 of class  TestClass */
#ifndef TOLUA_DISABLE_tolua_TestClass_TestClass_method300
static int tolua_TestClass_TestClass_method300(lua_State* tolua_S)
{
#ifndef TOLUA_RELEASE
 tolua_Error tolua_err;
 if (
   !tolua_isusertype(tolua_S,1,"TestClass",0,amp;tolua_err) ||
   !tolua_isnoobj(tolua_S,2,amp;tolua_err)
     )
  goto tolua_lerror;
 else
#endif
 {
  TestClass* self = (TestClass*)  tolua_tousertype(tolua_S,1,0);
#ifndef TOLUA_RELEASE
  if (!self) tolua_error(tolua_S,"invalid 'self' in function 'method3'", NULL);
#endif
  {
   self->method3();
  }
 }
 return 0;
#ifndef TOLUA_RELEASE
 tolua_lerror:
 tolua_error(tolua_S,"#ferror in function 'method3'.",amp;tolua_err);
 return 0;
#endif
}
#endif //#ifndef TOLUA_DISABLE

/* Open function */
TOLUA_API int tolua_TestClass_open (lua_State* tolua_S)
{
 tolua_open(tolua_S);
 tolua_reg_types(tolua_S);
 tolua_module(tolua_S,NULL,0);
 tolua_beginmodule(tolua_S,NULL);
  #ifdef __cplusplus
  tolua_cclass(tolua_S,"TestClass","TestClass","",tolua_collect_TestClass);
  #else
  tolua_cclass(tolua_S,"TestClass","TestClass","",NULL);
  #endif
  tolua_beginmodule(tolua_S,"TestClass");
   tolua_function(tolua_S,"new",tolua_TestClass_TestClass_new00);
   tolua_function(tolua_S,"new_local",tolua_TestClass_TestClass_new00_local);
   tolua_function(tolua_S,".call",tolua_TestClass_TestClass_new00_local);
   tolua_function(tolua_S,"method1",tolua_TestClass_TestClass_method100);
   tolua_function(tolua_S,"method2",tolua_TestClass_TestClass_method200);
   tolua_function(tolua_S,"method3",tolua_TestClass_TestClass_method300);
  tolua_endmodule(tolua_S);
 tolua_endmodule(tolua_S);
 return 1;
}


#if defined(LUA_VERSION_NUM) amp;amp; LUA_VERSION_NUM >= 501
 TOLUA_API int luaopen_TestClass (lua_State* tolua_S) {
 return tolua_TestClass_open(tolua_S);
};
#endif
  

Ответ №1:

Состояние Lua никогда явно не обрабатывается кодом Lua — оно неявное. Любой функции C , вызываемой Lua, не обязательно явно передавать состояние — она получает его как свой первый аргумент, который всегда передается Lua, независимо от других аргументов, потому что невозможно каким-либо образом взаимодействовать с Lua без lua_State* . Единственной причиной для этого было бы, если бы у вас было какое-то мета-состояние или, если вы выполняете что-то с помощью совместных подпрограмм Lua.

Глобальная функция кажется достаточно простой и вряд ли является источником ошибки. Вам нужно распечатать содержимое TestClass, чтобы убедиться, что в нем есть ожидаемое содержимое, и если нет, то это проблема, связанная с библиотекой привязки, и вам придется покопаться в их внутренностях, потому что этот код выглядит для меня так, как будто наиболее вероятная проблема заключается в том, что TestClass в таблице не имеет того, что вы ожидаете от нее иметь.

Комментарии:

1. Спасибо за ответ, я отредактировал сообщение, чтобы включить TestClass.cpp код.

2. Причина, по которой я передаю параметр lua_State * в конструктор, заключается в том, что я хочу, чтобы созданный объект сохранял его как атрибут, чтобы затем он мог использовать его для вызова самих функций lua. Мне пришла в голову эта идея до того, как я понял, что сгенерированный tolua код может передаваться в lua_State для меня, поэтому в настоящее время я экспериментирую, чтобы посмотреть, смогу ли я запустить аналогичный код без моих ухищрений, чтобы попытаться изолировать проблему.

Ответ №2:

Оказывается, единственной проблемой было то, что «lua2Function» было написано со строчной буквы F в сценарии. Код, который я вставил, на самом деле работает нормально. Как это ужасно неловко!

Думаю, я узнал, что tolua определенно заботится о передаче указателей lua_State, по крайней мере, в методы.