从参数中获取Lua函数

4
一个简单的生产示例。
protocol.onConnect(function() end, function () end, ...)

现在在c语言中,我想获取参数#1、#2中的函数。
在字符串、数字等中,我们可以使用(lua_getstring,...)来获取它们,但至少我没有找到如何获取函数。

int luaProtocolOnConnect(lua_State* L)
{
    int base_func // func #1
    int call_func // func #2
    ....
}
2个回答

6
你无法真正地“获得”一个 Lua 函数。Lua 函数和 Lua 表一样,都是纯 Lua 对象。因此,它们没有 C 或 C++ 的类似物。如果你想调用一个 Lua 函数,可以通过 lua_calllua_pcall 或类似的函数在 Lua 栈上进行操作。
所以你不能将 Lua 函数转换为 C++ 值。你能做的是使用各种方式对 Lua 函数进行操作,就像对所有 Lua 对象进行操作一样。
例如,假设你想要在 C++ 对象中存储一个 Lua 函数,然后稍后调用存储在其中的任何 Lua 函数。显然,你不能直接将 Lua 函数转换为 C++ 值。你可以将该 Lua 函数存储在 C++ 可以访问的位置。你使用某个具有 C++ 类比的值来引用存储的 Lua 函数。这个值必须对于你想要存储的每个对象都是独一无二的。在存储对象时获得的值将保存在你的 C++ 对象中。当取回 Lua 函数时,只需使用存储的值即可。
由于这是一项非常常见的操作,Lua 有办法来促进这一过程。第一个是 Lua 注册表,这是一个 C++ 可以访问但 Lua 代码不能访问的表(除非你给予它访问权限)。
第二个是 luaL_ref 系列函数。 luaL_ref 将栈顶的任何内容放入你提供的表中,并返回一个整数键,以便以后检索它。可以使用 lua_rawgeti 通过键从表中检索函数,luaL_unref 在完成使用时从表中删除引用的函数与对应的键。
因此,如果你想要存储这些函数,只需创建这样一个表,在注册表中将其放置在一个已知位置(以便你随时可以获取它),然后使用 luaL_ref 存储这些函数。当需要调用它们时,使用 lua_rawgeti 取回它们。在使用完成后,使用 luaL_unref 销毁它们即可。

有关内容:您知道将作为参数接收的lua_State引用存储到CFunction中是否安全吗?是否存在引用移动的风险? - Hibou57

5
您可以使用lua_isfunction函数检查是否为函数,使用lua_pushvalue将其值推送到堆栈顶部,然后使用luaL_ref(luaL_ref(L,LUA_REGISTRYINDEX);)将其转换为一个唯一的键,以便稍后引用该键来检索值(lua_rawgeti(L,LUA_REGISTRYINDEX,ref))并调用函数。

直接将事物引用到注册表中可能不是一个好主意,除非你的代码是在该Lua环境中唯一执行的C/C++代码。 - Nicol Bolas
1
我基本上同意,但在这种情况下,关键字保证是唯一的,我已经看到一些库这样做而没有问题(例如,winapi)。 OP可以根据需要替换自己的表。 - Paul Kulchenko
只有在“您不手动将整数键添加到表t”时,才能保证其唯一性。 - Nicol Bolas
@NicolBolas,是的,但注册表是私有的C端,无法从Lua端访问(除非C端提供此访问),因此这只是程序中任何数据所需的常规注意事项。而且注册表就是为此目的而设计的。 - Hibou57

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接