从C中查询Lua的userdata类型。
我有一个 Lua userdata 对象,它带有一个特定的元表类型(例如"stackoverflow.test"
)。我想从 C 代码中精确地检查它是哪种类型,并根据结果以不同的方式进行处理。是否有一个漂亮方便的函数(类似于luaL_checkudata
,但是如果答案不是你想要的,不报错),可以让我查询userdata的元表类型名称?如果没有,我猜我需要使用lua_getmetatable
,但是我不太清楚如何确定刚刚添加到堆栈中的元表的名称。
仅作澄清:我正在使用 Lua 5.1,在该版本中,luaL_checkudata
的行为已更改。我了解在 5.0 中它不会报错。
原文链接 https://stackoverflow.com/questions/726958
你可以在元表中存储一个标记字段,其中包含一个对于你的模块唯一的轻量级userdata值。
static const char *green_flavor = "green";
...
void my_setflavor(lua_State *L, void *flavor) {
lua_pushlightuserdata(L,flavor);
lua_pushlstring(L,"_flavor");
lua_rawset(L,-3);
}
void my_isflavor(lua_State *L, void *flavor) {
void *p = NULL;
lua_pushlstring(L,"_flavor");
lua_rawget(L,-2);
p = lua_touserdata(L,-1);
lua_pop(L,1);
return p == flavor;
}
然后,你可以使用my_setflavor(L,&green_flavor)
为堆栈顶部的表设置_flavor
字段,使用my_isflavor(L,&red_flavor)
来测试堆栈顶部的表的_flavor
字段。
使用这种方式,_flavor
字段只能采用由拥有符号green_flavor
的模块中的代码创建的值,并且查找字段并测试其值只需要除检索元表本身之外的一个表查找。请注意,变量green_flavor
的值并不重要,因为实际上只使用了变量的地址。
使用多个不同的风味变量作为哨兵值,可以使用_flavor
字段来区分几个相关的元表。
所有这些说完后,一个自然的问题是"为什么要这样做呢?"毕竟,元表可以轻松包含它需要获取适当行为所需的所有信息。 它可以容纳函数以及数据,这些函数可以像Lua一样从C中检索和调用。
userdata
必须要有元表,所以先获取元表;然后在注册表中查找您想要的名称。如果这两个对象是相同的,那么就找到了您要查找的类型。
您可以在 C 代码中按此类型分派,但我想要轻轻建议您指定元表的字段。存储在元表中的函数应该可以胜任此工作,但如果不行,如果您绝对必须在 C 代码中使用 switch
,那么请选择一个名称,用它索引到元表,并为每个元表分配一个可以在其上进行切换的小整数。
meta1.decision = 1
meta2.decision = 2
meta3.decision = 3
然后在您的 C 代码中
if (lua_getmetatable(L, 1)) {
lua_getfield(L, -1, "decision");
if (lua_isnumber(L, -1)) {
switch ((int) lua_tonumber(L, -1)) {
case 1: ... ; break;
case 2: ... ; break;
case 3: ... ; break;
}
return 0;
}
}
return luaL_error(L, "Userdata was not one of the expected types");
您将使用 lua_getmetatable
和 lua_equal
来测试表是否相同。
我认为,Lua 应该为这种类型扩展提供更多支持。在目前的版本中,实现这一点真正落在了 Lua/C(++) 封装系统的责任上。
在我最近完成的一个封装程序中(作为一个商业项目的一部分),我做了 class::instance(L,index)
来获取特定类型的 userdata 指针。换句话说,该方法检查它是否是 userdata,并且元表也是正确的。如果不是,它将返回 NULL。
Lua 可以帮助所有这些,方式是如果元表具有扩展类型信息的标准字段(例如 __type
)。这可以用来使 type()
本身返回 "userdata"、"xxx"(目前仅返回一个)。这将保持与大多数当前代码的兼容性。但这仅仅是假设(除非你做一个自定义的 type() 并自己实现它)。
- 如何在roblox studio中1:1导入真实世界的地形?
- 求解,lua_resume的第二次调用继续执行协程问题。
- 【上海普陀区】内向猫网络招募【Skynet游戏框架Lua后端程序员】
- SF爱好求教:如何用lua实现游戏内调用数据库函数实现账号密码注册?
- Lua实现网站后台开发
- LUA错误显式返回,社区常见的规约是怎么样的
- lua5.3下载库失败
- 请问如何实现文本框内容和某个网页搜索框内容连接,并把网页输出来的结果反馈到另外一个文本框上
- lua lanes多线程使用
- 一个kv数据库
- openresty 有没有比较轻量的 docker 镜像
- 想问一下,有大佬用过luacurl吗
- 在Lua执行过程中使用Load函数出现问题
- 为什么 neovim 里没有显示一些特殊字符?
- Lua比较两个表的值(不考虑键的顺序)
- 有个lua简单的项目,外包,有意者加微信 liuheng600456详谈,最好在成都
- 如何在 Visual Studio 2022 中运行 Lua 代码?
- addEventListener 返回 nil Lua
- Lua中获取用户配置主目录的跨平台方法
- 如何编写 Lua 模式将字符串(嵌套数组)转换为真正的数组?
我刚刚查看了
luaL_checkudata
函数的源代码,它基本上是使用lua_getmetatable
来获取userdata对象的metatable。然后使用lua_getfield
从注册表中获取给定类型名称,并使用lua_rawequal
调用进行比较。