从C访问lightuserdata

时间:2019-04-01 14:59:21

标签: c lua

我正在与C一起在资源非常有限的系统中使用Lua。

我正在使用的库为它创建的对象创建一些引用(作为指针),这对于以后访问这些对象很有用。为了向Lua公开该库的功能,在创建此类对象时,该引用将返回到Lua脚本。

用户可以根据自己的喜好存储此引用,因为这使得以后的调用非常方便。

示例案例:

ref = MyLib.createObject("some", arguments)
local ref = MyLib.createObject("some", arguments)
table_of_refs[45] = MyLib.createObject("some", arguments)
-- etc...

不幸的是,这些引用可能在Lua脚本范围之外(在C中)被销毁。因此,这些引用可能无效。

目前,我的代码可以毫无问题地处理这些无效引用。所有这些指针都需要在库中实际使用之前经过验证,因此代码是安全的。

但是,从Lua用户的角度看,这似乎有点令人困惑,因为无法确定该引用是否仍然有效((这不是很重要,但我仍然想对其进行改进)

我想要的是以下内容。我想从C迭代Lua存储的所有lightuserdata。如果lightuserdatum不再有效,请将其设置为nil。这样,下次使用时变量将为有效或为零,从而为用户提供了更好的API。

有什么办法可以做到这一点?我可以从Lua知道的C 所有 lightuserdata迭代(无论它们存储在哪里,本地/全局/表等),并进行修改吗?

2 个答案:

答案 0 :(得分:2)

无法从C访问局部lua变量。因此,即使您对某种类型的lua对象进行了迭代,也无法访问至少一个区域(局部变量)。

您可以遍历全局表中的所有内容,如Max在此处的答案所示:Loop through all Lua global variables in C++

如果要针对lua_islightuserdata进行测试,然后将lightuserdata的值与要删除的指针进行比较,那么您应该能够识别出想要的全局值。

lua_pushglobaltable(L); 
lua_pushnil(L);    
while (lua_next(L,-2) != 0) 
{
    if (lua_islightuserdata(L, -1))
    {
        //TODO: compare against the lightuserdata pointer value you are looking for
        void* mypointer = lua_touserdata(state, -1);

        name = lua_tostring(L,-2);  // Get key(-2) name
        //TODO: do whatever with the value; probably set to nil by name in the global table
    }
    lua_pop(L,1);
}
lua_pop(L,1); 

但是,如果要在表中搜索它,则必须包括lua_istable的附加检查,然后以相同的方式递归遍历表的值。

...
else if (lua_istable(L, -1)
{
    //TODO: iterate each value in the table searching for lightuserdata
    // or tables with further levels of recursion
}
...

但是,我认为,在MyLib上提供一种称为“ isValid”的方法会更直接,该方法会在使用该值之前返回该值是否仍然有效。

local ref = MyLib.createObject("some", arguments)
...
local isvalid = MyLib.isValid(ref)

那么您就不受本地范围的限制。另外,假设您仍然会在lua代码中进行nil检查(以查看值是否从您的下面更改了),那么就代码而言,这基本上不会花费您什么。

答案 1 :(得分:0)

我认为您在概念上已经走错了路。

为什么可以从C中销毁创建的对象?是Lua脚本触发了创建,因此也应该是Lua脚本触发了破坏。

您可以设置标志来指示对象的无效状态,而不是破坏对象。您可能还需要实现一种回调机制,以便C库可以通知Lua脚本有关无效对象的信息。

如果要维护大量数据,并且希望尽快重用内存,那么Lua对象可能只是指向真实数据的指针的包装器。然后,您可以独立地删除数据,并将指针设置为NULL,同时将其用作无效标志。

请注意,仅通过指针值本身检查指针有效性可能会严重失败:

SomeStruct* ptr = malloc(sizeof(SomeStruct));
// don't forget if(!ptr) error handling

SomeStruct* copy = ptr; // here C only, but might be stored in Lua!

SomeStruct* newPtr = malloc(sizeof(SomeStruct));
// by accident same address re-used as ptr once had!!!

if(isValid(copy))
{
    // but the struct originally referenced died long ago...
}
相关问题