2009-10-29 55 views
1

真的不知道怎么问那么裸请与我:)保存参考Lua的用户数据

#1的Lua:

local test = Test(); 

#2 C:

//creating "lua's test" 
luaL_newmetatable(L, "someTable"); 
lua_userdata *userData = (lua_userdata *)lua_newuserdata(L, sizeof(lua_userdata)); 

luaL_getmetatable(L, "someTable"); 
lua_setmetatable(L, -2); 

#3的Lua :

function test.newMethod() 
end 

#4 C:

//this part is not executed from Lua 
//what i have to have here from #2 to call "test.newMethod" and how to call it? 
//if userdata would be on stack i guess i could: 
luaL_getmetafield (L, 1, "newMethod"); 
lua_call(L, 0, 0); 
//but because this part is not executed by Lua call its not on stack. 

编辑:

将试图解释在伪代码更简单:

的Lua:

local test = Object(); 

C:

int Object(){ 
    ... 
    somePointer = luaL_newmetatable(...); //how to get this "somePointer"? maybe luaL_ref? 
    push ... 
} 

的Lua:让新的方法

function test.newMethod() 
    ... 
end 

在C一些事件(可以说定时器)触发C法

void triggeredCMethod(){ 
    //here i need to call test.newMethod 
    //if i would have here 'somePointer' and could push it to Lua stack i could find and call newMethod 
} 

所以问题是:如何用C存储指针一些Lua的对象(希望我需要的),由得到的Lua对象指针和调用方法,它

+0

让我看看我是否有这个权利。你有一个在Lua中定义的函数,并且你想传递一个你在C中创建的userdata参数。在创建userdata和你需要使用它之间可能会传递一些任意的时间,所以你可以只要创建它就立即将它推到Lua堆栈上。准确? – 2009-10-29 22:21:24

+0

和你的问题是? – 2009-10-30 01:27:09

回答

5

我假设你希望能够调用动态添加功能。这段代码应该相对简单地解释它。注意我不做太多的错误检查并做出一些假设,不要复制粘贴这个解决方案。

typedef struct 
{ 
    int number; 
    int reference; 
    lua_State *L; 
} TestUserdata; 

static int m_newindex(lua_State *L) 
{ 
    /* This is passed three values, first (at -3) is the object, bring this to the front */ 
    lua_getfenv(L, -3); 
    /* Now bring the second arg forward, the key */ 
    lua_pushvalue(L, -3); 
    /* And the third arg, the value */ 
    lua_pushvalue(L, -3); 
    /* And we're done */ 
    lua_rawset(L, -3); 

    return 0; 
} 

static int m_tostring(lua_State *L) 
{ 
    lua_pushstring(L, "TestUserdata"); 
    return 1; 
} 

static int callobject(lua_State *L) 
{ 
    /* Grab the object passed, check it's the right type */ 
    TestUserdata *data = luaL_checkudata(L, 1, "TestUserdata"); 

    /* Grab the function environment we gave it in createobject, and look in there for newmethod */ 
    lua_getfenv(L, -1); 
    lua_pushstring(L, "newmethod"); 
    lua_rawget(L, -2); 

    /* Call the function */ 
    lua_pushinteger(L, data->number); 
    lua_call(L, 1, 0); 

    return 0; 
} 

static const struct luaL_reg userdata_m[] = { 
    { "__newindex", m_newindex }, 
    { "__tostring", m_tostring }, 
    { NULL, NULL } 
}; 

int main (int argc, char *argv[]) 
{ 
    lua_State *L = luaL_newstate(); 
    luaL_openlibs(L); 

    /* Let's create us a userdatum metatable, and fill it up with goodies */ 
    luaL_newmetatable(L, "TestUserdata"); 
    /* Use luaL_register to fill up the metatable for us */ 
    luaL_register(L, NULL, userdata_m); 
    lua_pop(L, 1); /* Clean up the stack, we won't need the metatable left here */ 

    TestUserdata *data = lua_newuserdata(L, sizeof(TestUserdata)); 
    lua_pushvalue(L, -1); /* Copy for luaL_ref */ 
    int ref = luaL_ref(L, LUA_REGISTRYINDEX); 
    data->reference = ref; 
    data->number = 42; 
    data->L = L; 

    /* Load the metatable from before and 'give' it to this userdatum */ 
    luaL_getmetatable(L, "TestUserdata"); 
    lua_setmetatable(L, -2); 

    /* Give this object an empty function environment */ 
    lua_newtable(L); 
    lua_setfenv(L, -2); 

    lua_setglobal(L, "test"); 

    luaL_dostring(L, "function test.newmethod(num) print(num) end"); 

    /* Now provided we have the object, we can call any method defined anywhere */ 
    lua_rawgeti(data->L, LUA_REGISTRYINDEX, data->reference); 
    lua_getfenv(data->L, -1); 
    lua_pushstring(data->L, "newmethod"); 
    lua_rawget(data->L, -2); 
    lua_remove(data->L, -2); 

    if(lua_isfunction(data->L, -1) == 1) 
    { 
     lua_pushinteger(data->L, data->number); 

     lua_pcall(data->L, 1, 0, 0); 
    } 

    lua_close(L); 

    return 0; 
} 

检查一下,我认为这就是你要做的。

+0

你的解决方案的问题是你从Lua调用“callobject(test)”。这样做你可以将所有需要的东西放到Lua堆栈中。 如何从Lua做同样的调用?基本上我的问题是如何通过不是来自Lua的“测试”对象。 – RolandasR 2009-10-30 10:31:35

+0

这种情况类似。让我为你更新... – jsimmons 2009-10-30 11:23:44

+0

是的,非常感谢你。 – RolandasR 2009-10-31 08:50:36

0

如果你想要的是调用的Lua函数'test.newMethod()',那么我想你想的这个量级上的东西:

lua_getglobal(L, "test"); 
lua_getfield(L, -1, "newMethod"); 
lua_call(L, 0, 0); 

我不t t嗨,你需要弄乱metatable或userdata。

但是你的问题的力是不完全清楚我...