2011-04-05 248 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指針傳入方法,至少。

相關問題