【问题标题】:Lua C API push existing pointersLua C API 推送现有指针
【发布时间】:2013-02-08 22:24:27
【问题描述】:

假设我有一个来自 C 端的指针,我希望以用户数据的形式将它推入 Lua 堆栈。在不牺牲指定特定元表的能力的情况下,最好的方法是什么?

我最初的想法是使用轻量级用户数据,但从我读过的here 来看,所有轻量级用户数据共享一个公共元表。这是不可取的,因为它会强制我所有的 c 面对象都采取共同的行为。

考虑到我希望为 Lua 分配的对象重用元表,只需将不同的 this 指针传递给元方法,我的第二个想法是将人工 this 指针附加到 userdata 对象。

struct ud
{               
    struct T* ptr;
    struct T data;
};

struct ud* p = (struct ud*)lua_newuserdata(L, sizeof(struct ud));
p->ptr = &(p->data);

或者,在推送轻量用户数据的情况下

struct T object;
struct T** p = (struct T**)lua_newuserdata(L, sizeof(struct T*));
*p = &object;

是否推荐附加 this 指针,或者是否有更 API 友好的替代方案?我的最终目标是简单地将现有指针推送到 Lua,并将元表与它关联,这样元表可以被重用和轻量用户数据重用。

【问题讨论】:

  • 你不能用void*s 做指针运算。那么您究竟希望您的第一个代码示例做什么?
  • 那是我的一个错误。我忘记了指针算术在 void* 上是非标准的。目的是将 this 指针附加到 userdata,然后是结构本身。然后,将 this 指针设置为紧随其后的位置,我希望在该位置分配结构。我将编辑我的代码以以标准方式反映这一点。

标签: c api lua


【解决方案1】:

一种常见的(但不是唯一的)方法是使用一种称为“盒装指针”的技术。这个想法是你分配一个足够大的用户数据来保存指针,然后将你的元表等附加到它。

void push_pointer(lua_State *L, void *p) {
    void **bp = lua_newuserdata(L, sizeof(p));
    *bp = p;

    // setup metatable, etc
}

然后通过元表调用的函数将在堆栈上接收这个用户数据,然后你从中解包原始指针。

// called via metatable
int some_function(lua_State *L) {
    assert(lua_type(L, 1) == LUA_TUSERDATA);
    void **bp = lua_touserdata(L, 1);
    void *p = *bp;

    // do stuff with p
}

在执行此操作时,您必须考虑以下几点:

  • 对象生命周期。如果 C 端对象被释放,而 Lua 端的某些东西引用了它的用户日期,那么你将有一个悬空指针。如果这是可能发生的事情,那么您需要一种方法来处理它。我自己处理了这个问题,方法是拥有一个“活动”C 对象的注册表,我可以在尝试使用指针之前对其进行检查。

  • 用户数据相等。由于您为每个指针推送一个新的用户数据,因此具有相同指针的两个用户数据在 Lua 中不会比较相等。如果这对您很重要,那么您可以通过几种方法来处理它。 __eq 元方法是最简单的,但并不总是合适的。我使用上面提到的相同对象注册表来提供指针->用户数据映射,然后,在推送时,如果我已经有指针的用户数据,我只是推送它而不是创建一个新的。

    李>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-07-05
    • 2012-06-28
    • 2014-09-14
    • 1970-01-01
    • 2011-03-29
    • 2021-12-27
    • 2013-02-08
    • 2020-11-17
    相关资源
    最近更新 更多