代码之家  ›  专栏  ›  技术社区  ›  RolandasR

保存对Lua用户数据的引用

  •  1
  • RolandasR  · 技术社区  · 15 年前

    #1卢阿:

    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卢阿:

    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(); 
    

    丙:

    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对象并在其中调用方法

    2 回复  |  直到 6 年前
        1
  •  5
  •   jsimmons    15 年前

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

    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;
    }
    

    检查一下,我想这就是你想要的。

        2
  •  0
  •   Norman Ramsey    15 年前

    如果您只想调用lua函数“test.newmethod()”,那么我认为您需要以下顺序的函数:

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

    我认为您不需要处理元表或用户数据。

    然而,我并不完全清楚你的问题的力量…