Pregunta

Now I want to pass a void* pointer to Lua, use userdata? How to do this?

BTW, I used luabind, but it cannot pass a void* pointer to Lua stack, this is annoying! Could you guys help me?

struct Event
{
     A* a;
     B* b;
     ...
};

Event *e;
void* instance = (void*)e;


// param is a parameter that is passed from Lua script. param is a Event object. And I cast it into a void* type
string Answer(void* param)
{
    WorkEvent *pWorkEvent = static_cast<WorkEvent*>(param);
    ASSERT_RET(pWorkEvent, NULL);

    string call_id = pWorkEvent->GetCallId();
    CCmThreadManager::TType thrd_id =  pWorkEvent->GetHandleThrdID();
    Coroutine *pco    = pWorkEvent->m_pco;
¿Fue útil?

Solución

Let's answer your actual question before getting into why you shouldn't be doing this.

LuaBind is a tool for binding C++ functions and objects to Lua. A void* is neither a function nor an object. It is, quite literally, a pointer to nothing. As such, it has no real meaning to LuaBind. So you cannot pass one directly.

You can however return a luabind::object, which can represent any Lua value. For example, a Lua userdata. Which means you can create some light userdata from your void*, stick it into a luabind::object and return it from a function you register with LuaBind.

luabind::object RegisteredFunction(..., lua_State *L)
{
  void *return_value = ...;

  lua_pushlightuserdata(L, return_value);
  luabind::object ret(luabind::from_stack(L, -1));
  lua_pop(L, 1);
  return ret;
}

To allow Lua to pass it back so that you can retrieve it, simply create a function that takes a luabind::object as the void* parameter:

void OtherRegisteredFunction(..., luabind::object obj, ...)
{
  assert(luabind::type(obj) == LUA_TLIGHTUSERDATA);
  obj.push();
  void *param = lua_touserdata(obj.interpreter(), -1);
  lua_pop(obj.interpreter(), 1);
}

So that's how you pass that kind of data. Now here's why you shouldn't do that.

First, your code is broken:

WorkEvent *pWorkEvent = static_cast<WorkEvent*>(param);

Assuming that your param came from this line, void* instance = (void*)e, C++ doesn't guarantee this to work. If you cast an object to a void*, C++ only provides a guarantee of getting something useful back if you cast it to the exact same object as it was before.

You started with an Event*, then converted it to a void*. The only legal operation you can do is to cast it back to an Event*. Even if WorkEvent is a derived class of Event, you cannot cast it directly to that class. You have to turn it back into an Event* first. Also, you should use a dynamic_cast to do the down-cast once you have an Event*.

Second, stop using void*s for this. If all of your events are derived from Event*, then just pass an Event* and use dynamic_cast where appropriate. If they aren't, then you should be using boost::any (LuaBind requires Boost, so obviously you're using it already). Not only will you be able to bind that to LuaBind (since it's an actual type), it's much more natural to work with.

And it has built-in protection from exactly the problem your code had before; if you tried to cast it to a WorkEvent when it was given only an Event, it would throw an exception.

Otros consejos

We don't use void* in lua directly. Here we use c function to call lua function then lua function to call c function in the 1st c we pass a void* to lua function then lua pass the void* to 2nd c function.

But we find that we can't pass a void* to lua when we add the default_converter void*.

namespace luabind
{
    template <>
    struct default_converter<void*> : native_converter_base<void*>
    {
        static int compute_score(lua_State * L, int index)
        {
            // this function will return 0 or -1 (int)
            return lua_type(L, index) == LUA_TLIGHTUSERDATA ? 0 : -1;
        }
        void* from(lua_State * L, int index)
        {
            return lua_touserdata(L, index);
        }
        void to(lua_State * L, void* value)
        {
            lua_pushlightuserdata(L, value);
        }
    };

} // namespace luabind
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top