从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

点赞
stackoverflow用户4397
stackoverflow用户4397

我刚刚查看了 luaL_checkudata 函数的源代码,它基本上是使用 lua_getmetatable 来获取userdata对象的metatable。然后使用 lua_getfield 从注册表中获取给定类型名称,并使用 lua_rawequal 调用进行比较。

2009-04-07 18:17:30
stackoverflow用户68204
stackoverflow用户68204

你可以在元表中存储一个标记字段,其中包含一个对于你的模块唯一的轻量级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中检索和调用。

2009-04-08 01:43:45
stackoverflow用户41661
stackoverflow用户41661

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");
2009-04-09 02:05:56
stackoverflow用户14455
stackoverflow用户14455

您将使用 lua_getmetatablelua_equal 来测试表是否相同。

我认为,Lua 应该为这种类型扩展提供更多支持。在目前的版本中,实现这一点真正落在了 Lua/C(++) 封装系统的责任上。

在我最近完成的一个封装程序中(作为一个商业项目的一部分),我做了 class::instance(L,index) 来获取特定类型的 userdata 指针。换句话说,该方法检查它是否是 userdata,并且元表也是正确的。如果不是,它将返回 NULL。

Lua 可以帮助所有这些,方式是如果元表具有扩展类型信息的标准字段(例如 __type)。这可以用来使 type() 本身返回 "userdata"、"xxx"(目前仅返回一个)。这将保持与大多数当前代码的兼容性。但这仅仅是假设(除非你做一个自定义的 type() 并自己实现它)。

2009-04-09 07:20:48