lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]

Hi Thanks for taking the time to type out that example. I found it much easier to understand than the examples I had found on the net.  I looked up all the API calls and it and documented it in more detail, the code worked perfectly first time when I tested it. one thing to note:
all light userdata values in a same lua (global) State share a same metatable. in other words, metatable for light userdata is not "per object".
I was less clear about the implication of this limitation, I tried expanding the code example, so that I added a new struct variable myBoo using the same structure type. As expected this worked OK as the foo_indexer is common for the 2 variables. both myFoo and myBoo variables returned unique and correct numbers in LuaI then added a new structure type and variable with 3 floats instead of 3 ints. I wrote a new indexer for that and installed it after the myFoo indexer was setup. As I half expected, this new float structure access worked OK, but broke the myFoo and myBoo variable access. Does my understanding sound correct on that ? That was expected from the limitation you mentioned ? OK, so that kind of makes light userdata pretty much useless for real world examples where more than one structure type is needed, or am I missing something here, it sounds too big a limitation so I am doubting my understanding is correct. I guess I need to look at using full userdata now as an a
 lternative way to go, I didnt really follow Michals follow up post , but I have only read it once so far, I need to re-read that one Thanks again for your help Geoff
 Date: Sun, 28 Aug 2011 00:54:06 +0800
Subject: Re: Struggling with userdata concepts


    于 2011-8-27 22:46, Jeff Smith 写道:


        I have done a little bit of work with Lua C API bindings, that
        all went pretty smoothly, but I am having great difficulty
        understanding userdata and light userdata. I have not found the
        examples online easy to follow or very helpful, so I am hoping
        someone on this list might be kind enough to help out. The
        example I want to implement is to expose to Lua a C structure
        so Lua can access the individual data variables


        struct foo


           int x;

           int y;

           int z;



        struct foo myFoo;



        -- In Lua I want to do something like

        local x = myFoo.x

        local y = myFoo.y



        As I dont want Lua to create myFoo objects, or manage their
        memory, I am thinking this example should be implemented with
        light userdata, but dont know how to go about this.


        This example is a slightly simplified version of what I need to
        do,  in reality I have a C array, such as    struct foo

        so ultimately I would want to do something like this in Lua,  
         local x = myFoo[2].x.


        I am not sure how much the array version complicates the
        solution for the non array version ?


        Any example C API code and explanation would be most appreciated
        if anyone fancies brushing up their skills to try this out ?


        Regards Geoff  




    a light userdata is just a "pointer". lua code can only do
    assignment and test the equality of userdata, all other operations
    (e.g. index) must be defined in C code.


    simply saying, you store a C pointer into lua using light userdata,
    and define various operations that can be access from lua as



    for instance, you know, the lua code `myFoo.x' is actually syntax
    suggar for 'myFoo["x"]', which is a *index* operation with a key of
    the "string" type. 


    so if you want to access myFoo.x and myFoo.y from lua like this


     local x = myFoo.x

     local y = myFoo.y



    you should :


    1.  put a light userdata, or pointer (which points to the C struct
    `myFoo'), into lua, with the (global) name `myFoo' 


        lua_pushlightuserdata(L, (void*)&myFoo);

        lua_setglobal(L, "myFoo");


    2.  define the *index* operation (e.g. as a lua_CFunction) that
    accept the string "x" and "y" as key and return the x and y member
    of the C struct respectively.


        int foo_indexer (lua_State *L) {

            struct foo * p = lua_touserdata(L, 1);

            const char *key = lua_tostring(L, 2);

            if (p != NULL & key != NULL) {

                if ( key[0] == 'x' && key[1] == '\0') {      //
    key is "x"

                    lua_pushinteger(L, p->x);

                    return 1;


                else if ( key[0] == 'y' && key[1] == '\0') {  //
    key is "y"

                    lua_pushinteger(L, p->y);

                    return 1;



            return 0;



    3.  assiociate the index operation with the userdata. through
    metamethod __index


        lua_getglobal(L, "myFoo");


        lua_pushcfunction(L, &foo_indexer);

        lua_setfield(L, -2, "__index");

        lua_setmetatable(L, -2);

        lua_pop(L, -1);



    then,  in lua, the global myFoo is now a lightuser data.

    but lua code can only assign it to other variable, or compare it
    with other value for equality, or index it,

    all other operations would give a error, since we have only defined
    the `__index' metamethod.


        local x = myFoo.x

           -- metacall foo_indexer(myFoo, "x")


        mt = getmetatable(myFoo)

            -- mt.__index == foo_indexer


        print(type(x), type(myFoo["y"]), type(,

           -- would print : Number Number Nil Nil


        myBar = myFoo

           -- assignment


        assert( myBar == myFoo)

           -- equality test


        myFoo.x = 100

            -- issue a error message something like "newindex operation
    is not defined"



    one thing to note:

    all light userdata values in a same lua (global) State share a same

    in other words, metatable for light userdata is not "per object".




    the code I show is demostrating and not tested.

    the important thing is to understand the concepts.


    Hopefully may help.