【问题标题】:Lua How to pass a void* pointer to lua in C++ && pass it back to C++Lua 如何在 C++ 中将 void* 指针传递给 lua && 将其传递回 C++
【发布时间】:2012-11-08 04:08:29
【问题描述】:

现在我想将void* 指针传递给Lua,使用userdata? 如何做到这一点?

顺便说一句,我使用了 luabind,但它不能将 void* 指针传递给 Lua 堆栈,这很烦人!你们能帮帮我吗?

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;

【问题讨论】:

  • 你尝试了什么?请显示您的代码。哪个版本的lua 在哪个系统上?
  • string Answer(void* param) { WorkEvent *pWorkEvent = static_cast(param); ASSERT_RET(pWorkEvent, NULL);字符串 call_id = pWorkEvent->GetCallId(); CCmThreadManager::TType thrd_id = pWorkEvent->GetHandleThrdID();协程 *pco = pWorkEvent->m_pco;
  • 请编辑您的问题并将您的代码放在问题中,而不是在 cmets 中。
  • 相关代码我已经贴出来了。
  • 你试过阅读Programming in Lua吗?那么,为什么在使用 LuaBind 时要传递一个 void* 呢? LuaBind 在那里,因此您可以安全地从 Lua 操作 C++ 对象。

标签: pointers lua luabind


【解决方案1】:

在讨论为什么不应该这样做之前,让我们先回答你的实际问题。

LuaBind 是一个将 C++ 函数和对象绑定到 Lua 的工具。 void* 既不是函数也不是对象。从字面上看,它是一个指向 nothing 的指针。因此,它对 LuaBind 没有真正的意义。所以不能直接传一个。

可以返回一个luabind::object,它可以代表任何Lua值。例如,一个 Lua 用户数据。这意味着您可以从 void* 创建一些轻量级用户数据,将其粘贴到 luabind::object 中,然后从您注册到 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;
}

要让 Lua 将其传回以便您检索它,只需创建一个函数,该函数将 luabind::object 作为 void* 参数:

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

这就是您传递此类数据的方式。现在这就是你不应该这样做的原因。

首先,您的代码损坏

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

假设您的param 来自这一行,void* instance = (void*)e,C++ 不保证它可以工作。如果您将一个对象转换为 void*,C++ only 提供了一个保证,如果您将它转换为 与以前完全相同的对象,则可以得到有用的东西。

您从 Event* 开始,然后将其转换为 void*。您可以做的唯一合法操作是将其转换回Event*。即使WorkEventEvent 的派生类,您也不能将其直接 强制转换为该类。您必须先将其转回Event*。此外,一旦您拥有Event*,您应该使用dynamic_cast 进行向下转换。

其次,停止使用void*s。如果您的所有事件都源自Event*,那么只需传递Event* 并在适当的地方使用dynamic_cast。如果不是,那么您应该是using boost::any(LuaBind 需要 Boost,所以显然您已经在使用它了)。您不仅可以将它绑定到 LuaBind(因为它是一个实际类型),而且使用起来更加自然。

而且它具有内置保护功能,可以避免您的代码之前遇到的问题;如果您尝试将其转换为 WorkEvent,而它只被赋予了 Event,则会引发异常。

【讨论】:

  • 好的,我明白了。我必须找到另一种方法来解决我的问题。谢谢你。
【解决方案2】:

我们不直接在 lua 中使用 void*。 这里我们使用c函数调用lua函数然后lua函数调用c函数 在第一个 c 中,我们将 void* 传递给 lua 函数 然后 lua 将 void* 传递给第二个 c 函数。

但是我们发现我们不能将 void* 传递给 lua 当我们添加 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

【讨论】:

    猜你喜欢
    • 2011-11-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-02
    • 2013-04-14
    • 2015-03-13
    • 1970-01-01
    • 2013-07-24
    相关资源
    最近更新 更多