2011-04-05 252 views
1

我试图从C++调用lua函数,并且不断收到错误消息“错误:尝试调用nil值”。“尝试调用lua脚本时尝试调用nil值”

lua函数创建一个C++对象,然后调用它的一个方法,胶水代码已经用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); 

由于胶水代码似乎表明我不需要那样做,因此:

/* 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 

而产生的错误信息似乎证实了我的理论:“函数错误new”。参数#2是'userdata'; '[no object]'expected。“ 即它不期望/不需要我通过那个lua_State指针

我很茫然,我很难找到问题的解决方案lua,因为在tolua ++的基础上,教程/文档似乎很薄弱,但现在改变绑定库已经太晚了。

任何帮助都会非常感谢,我希望我已经提供了足够的诊断问题。

编辑:这是我的TestClass.cpp代码(你可以忽略方法1,2和3,因为它们似乎没有被调用,因为这个错误r):

#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 

回答

0

Lua状态永远不会被Lua代码显式处理 - 它是隐含的。由Lua调用的任何C++函数都不需要显式地让它通过它获取它的状态,因为它的第一个参数总是由Lua传递,而不管其他参数如何,因为不可能以任何方式与Lua进行交互,而不需要lua_State* 。这样做的唯一理由是如果你有某种元状态,或者如果你正在做Lua的合作例程。

全局函数似乎很简单,不太可能是错误的根源。你需要打印TestClass的内容来验证它是否具有期望的内容,如果没有,那么这是一个绑定的库特定问题,你将不得不深入到它们的内部,因为那些代码在我看来就像是最可能的问题TestClass表没有你期望的那样。

+0

感谢您的回复,我编辑帖子以包含TestClass.cpp代码。 – Kinto 2011-04-06 13:00:22

+0

我将lua_State *参数传递给构造函数的原因是因为我希望创建的对象将其作为属性存储,因此可以使用它来调用lua函数本身。在我意识到tolua ++生成的代码可能会在我的lua_State中传递之前,我提出了这个想法,因此我正在试验,看看我是否可以在没有我的诡计的情况下运行类似的代码来尝试隔离问题。 – Kinto 2011-04-06 13:04:02

1

事实证明唯一的问题是“lua2Function”在脚本中拼写了一个小写的F。我粘贴的代码实际上工作正常。多么彻底的尴尬!

我想我已经了解到,tolua ++肯定会照顾将lua_State指针传入方法,至少。

相关问题