从C访问lightuserdata

问题描述 投票:2回答:2

我在一个资源有限的系统中使用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
2个回答
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代码中无论如何都要进行零检查(以查看值是否从您的下方更改),这在代码方面基本上没有任何成本。


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...
}
© www.soinside.com 2019 - 2024. All rights reserved.