从C中查询Lua的userdata类型。
我有一个 Lua userdata 对象,它带有一个特定的元表类型(例如"stackoverflow.test")。我想从 C 代码中精确地检查它是哪种类型,并根据结果以不同的方式进行处理。是否有一个漂亮方便的函数(类似于luaL_checkudata,但是如果答案不是你想要的,不报错),可以让我查询userdata的元表类型名称?如果没有,我猜我需要使用lua_getmetatable,但是我不太清楚如何确定刚刚添加到堆栈中的元表的名称。
仅作澄清:我正在使用 Lua 5.1,在该版本中,luaL_checkudata的行为已更改。我了解在 5.0 中它不会报错。
你可以在元表中存储一个标记字段,其中包含一个对于你的模块唯一的轻量级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() 并自己实现它)。
- 如何将两个不同的lua文件合成一个 东西有点长 大佬请耐心看完 我是小白研究几天了都没搞定
 - 如何在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中获取用户配置主目录的跨平台方法
 
我刚刚查看了
luaL_checkudata函数的源代码,它基本上是使用lua_getmetatable来获取userdata对象的metatable。然后使用lua_getfield从注册表中获取给定类型名称,并使用lua_rawequal调用进行比较。