简体   繁体   English

尝试调用lua脚本时出现“错误:尝试调用nil值”

[英]“Error: attempt to call a nil value” when trying to call lua script

I'm trying to call a lua function from C++ and I keep getting the error message "Error: attempt to call a nil value". 我正在尝试从C ++调用lua函数,并且不断收到错误消息“错误:尝试调用nil值”。

The lua function creates a C++ object and then calls one of its methods, the glue code has been generated with tolua++. lua函数创建一个C ++对象,然后调用其方法之一,该胶合代码已使用tolua ++生成。 When calling the lua function I pass in a lua_State pointer, as the C++ class needs one for its constructor, which the lua function hands to it. 当调用lua函数时,我传入了lua_State指针,因为C ++类的构造函数需要一个lua_State指针,而lua函数会将其传递给它。

But as far as I can tell it never gets that far, it simply doesn't run the script at all. 但是据我所知,它永远也不会运行脚本。 At least the error doesn't reference any line numbers in the script. 至少该错误没有引用脚本中的任何行号。

Here is the C++ code calling the function: 这是调用该函数的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;
}

Here is the lua script: 这是lua脚本:

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

I'm fairly sure it's not something as simple as forgetting to do: 我敢肯定,这不像忘记做那么简单:

tclass = TestClass:new(lstate);

As the glue code seems to indicate I don't need to do that, here: 正如胶水代码似乎表明我不需要这样做,在这里:

/* 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,&tolua_err) ||
     !tolua_isnoobj(tolua_S,2,&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'.",&tolua_err);
 return 0;
#endif
}
#endif //#ifndef TOLUA_DISABLE

And the error message THAT produces seems to confirm my theory: "error in function 'new'. argument #2 is 'userdata'; '[no object]' expected." THAT产生的错误消息似乎证实了我的理论:“函数'new'中的错误。参数2是'userdata';应该是'[no object]'”。 ie it wasn't expecting/doesn't need me to pass in that lua_State pointer 即,没想到/不需要我传递那个lua_State指针

I'm at a loss, I have a lot of trouble finding solutions to problems with lua because tutorials/documentation seem to be pretty thin on the ground where tolua++ is concerned, but it's too late to change binding library now. 我很茫然,我很难找到解决lua问题的解决方案,因为在涉及tolua ++方面,教程/文档似乎很薄,但是现在更改绑定库为时已晚。

Any help would be much appreciated, I hope I've provided enough to diagnose the problem. 任何帮助将不胜感激,我希望我已提供足够的诊断问题的方法。

EDIT: Here's my TestClass.cpp code (you can probably ignore method1, 2 and 3 as they don't seem to be called because of this error): 编辑:这是我的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,&tolua_err) ||
     !tolua_isnoobj(tolua_S,2,&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'.",&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,&tolua_err) ||
     !tolua_isnoobj(tolua_S,2,&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'.",&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,&tolua_err) ||
     !tolua_isnoobj(tolua_S,2,&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'.",&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,&tolua_err) ||
     !tolua_isnumber(tolua_S,2,0,&tolua_err) ||
     !tolua_isnoobj(tolua_S,3,&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'.",&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,&tolua_err) ||
   !tolua_isnoobj(tolua_S,2,&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'.",&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) && LUA_VERSION_NUM >= 501
 TOLUA_API int luaopen_TestClass (lua_State* tolua_S) {
 return tolua_TestClass_open(tolua_S);
};
#endif

It turns out the only problem was that "lua2Function" was spelt with a lower-case F in the script. 事实证明,唯一的问题是脚本中的lua2Function拼写为小写F。 The code as I've pasted it actually works fine. 我粘贴的代码实际上可以正常工作。 How thoroughly embarrassing! 多么彻底的尴尬!

I guess I've learnt that tolua++ definitely DOES take care of passing lua_State pointers into methods, at least. 我想我已经了解到,至少tolua ++确实确实负责将lua_State指针传递给方法。

The Lua state is never explicitly handled by Lua code- it is implicit. Lua状态永远不会由Lua代码显式处理-它是隐式的。 Any C++ function called by Lua does not need to explicitly have the state passed in- it gets it as it's first argument which is always passed by Lua, regardless of the other arguments, because it's impossible to interact with Lua in any way without the lua_State* . Lua调用的任何C ++函数都不需要显式传递状态-它会获得它作为第一个参数(无论其他参数如何)始终由Lua传递的第一个参数,因为没有lua_State*就无法以任何方式与Lua进行交互lua_State* The only reason to do this would be if you have some kind of meta-state, or, if you're doing things with Lua's co-operative co-routines. 这样做的唯一原因是,如果您具有某种元状态,或者正在使用Lua的合作式协作程序进行操作。

The global function seems simple enough and not likely the source of error. 全局函数似乎足够简单,并且不太可能是错误的根源。 You need to print the contents of TestClass to verify that it has the contents expected, and if not, then this is a binding library specific problem and you will have to dig into their internals, because that code looks to me like the most likely problem is that TestClass the table does not have what you're expecting for it to have. 您需要打印TestClass的内容以验证它是否具有预期的内容,否则,这是绑定库特有的问题,您必须深入研究其内部,因为在我看来,该代码看起来像是最可能出现的问题是TestClass表没有您期望的表。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM