从C访问lightuserdata

从C访问lightuserdata,c,lua,C,Lua,我在一个资源非常有限的系统中使用Lua,与C结合使用 我使用的库创建了一些指向它创建的对象的引用(作为指针),这些引用对于以后访问这些对象很有用。为了向Lua公开这个库的功能,当创建这样一个对象时,这个引用将返回到Lua脚本 用户可以根据自己的喜好存储此引用,因为这使得以后的调用非常方便 示例案例: ref = MyLib.createObject("some", arguments) local ref = MyLib.createObject("some", arguments) table

我在一个资源非常有限的系统中使用Lua,与C结合使用

我使用的库创建了一些指向它创建的对象的引用(作为指针),这些引用对于以后访问这些对象很有用。为了向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


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

无法从C访问本地Lua变量。因此,即使您迭代了特定类型的Lua对象,您也无法访问至少一个区域(局部变量)

您可以遍历全局表中的所有内容,如Max的回答所示:

如果要针对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检查(以查看是否从您下面更改了值),这在代码方面基本不需要花费任何费用。

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

为什么创建的对象可以从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...
}
对不起,“MyLib”是一个糟糕的名称选择…事实上,它不是我的库,而是第三方库,所以我想避免任何修改。但我明白了。