Lua C API推送现有指针

The*_*ski 3 c api lua

假设我有一个 C 端拥有的指针,我希望以用户数据的形式将其推送到 Lua 堆栈上。在不牺牲指定特定元表的能力的情况下,实现此目的的最佳方法是什么?

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

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

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

struct ud* p = (struct ud*)lua_newuserdata(L, sizeof(struct ud));
p->ptr = &(p->data);
Run Code Online (Sandbox Code Playgroud)

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

struct T object;
struct T** p = (struct T**)lua_newuserdata(L, sizeof(struct T*));
*p = &object;
Run Code Online (Sandbox Code Playgroud)

是否建议附加 this 指针,或者是否有更 API 友好的替代方案?我的最终目标只是将现有的指针推送到 Lua,并将元表与其关联起来,以便元表可以重用于重型和轻型用户数据。

Rob*_*b N 5

执行此操作的常见(但不是唯一)方法是使用称为“装箱指针”的技术。这个想法是,您分配一个足够大的用户数据来容纳指针,然后将您的元表等附加到它。

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

    // setup metatable, etc
}
Run Code Online (Sandbox Code Playgroud)

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

// 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
}
Run Code Online (Sandbox Code Playgroud)

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

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

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