如何在userdata中存储值类型? [英] How to store a value type in a userdata?

查看:179
本文介绍了如何在userdata中存储值类型?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这篇SO文章是同样的事情,但答案是无益的,因为答案在Lua,问题是关于C-API。所以我再问一次。希望其他人会受益于这个问题。

This SO article is the same thing, but the answer is unhelpful because the answer was in Lua and the question was about the C-API. So I'm asking again. Hopefully, others will benefit from this question.

我实际上有两个问题(我不能让一个z工作,我不能得到helloworld ()to work)

I'm actually having 2 problems (I can't get y an z to work, and I can't get helloworld() to work)

我想尝试到这里:

local x = MyCBoundLib.GetSomething()
print(x.y)
print(x.z)


b $ b

其中 x 是一个userdata。我不断获得尝试索引一个userdata值

Where x is a userdata. I keep getting attempt to index a userdata value

我知道userdata在没有metatable的情况下是不可索引的,因为它是C / C ++数据

在我的C代码中,我会这样做,尝试并包装该对象。

In my C-code, I do something like this to try and wrap the object.

int push_Something(lua_State *L, void *object)
{
    struct SomethingWrapper *w = (struct SomethingWrapper *)lua_newuserdata(L, sizeof(struct SomethingWrapper));
    w->object = object;

    luaL_setmetatable(L, "Something");
    return 1;
}



以前,我试图注册一个名为 Something ,像这样:

luaL_newmetatable(L, "Something");
lua_pushvalue(L, -1);
lua_setfield(L, -2, "__index");
luaL_setfuncs(L, some_funcs, 0);
lua_pop(L, 1);

其中 some_funcs 具有:

static luaL_Reg const some_funcs [] =
{
    { "helloworld",     l_helloworld },
    { NULL, NULL }
};

如果我尝试 print(x.helloworld()),我得到相同的错误:尝试索引一个userdata值

If I try print(x.helloworld()), I get the same error: attempt to index a userdata value

我知道如何正确附加值类型 y z

In none of my code do I know how to properly attach the value type y or z.

推荐答案

首先, helloworld 您的代码工作原理:

First, for helloworld your code works:

/* file: hw.c
 * on Debian/Ubuntu compile with:
 *  `gcc -I/usr/include/lua5.2 -fpic -shared -o hw.so hw.c`
 */
#include <lua.h>
#include <lauxlib.h>

struct SomethingWrapper {
  void *object;
};

static int l_helloworld(lua_State *L) {
  lua_pushliteral(L, "Hello World!");
  return 1;
}

static luaL_Reg const some_funcs[] = {
  { "helloworld", l_helloworld },
  { NULL, NULL }
};

int push_Something(lua_State *L, void *object) {
  struct SomethingWrapper *w = lua_newuserdata(L, sizeof(*w));
  w->object = object;
  luaL_setmetatable(L, "Something");
  return 1;
}

int luaopen_hw(lua_State *L) {
  luaL_newmetatable(L, "Something");
  lua_pushvalue(L, -1);
  lua_setfield(L, -2, "__index");
  luaL_setfuncs(L, some_funcs, 0);
  lua_pop(L, 1);

  push_Something(L, NULL);
  return 1;
}

和测试脚本:

-- file: hwtest.lua
local x = require( "hw" )
print( x.helloworld() )

输出为:


世界!

Hello World!

要访问userdata上的属性,您需要设置 __ index 一个函数而不是一个表。每当您尝试访问userdata上的字段时,将使用两个参数(userdata和键)调用该函数,您可以查询您的C对象并推送所需的结果。

For accessing properties on a userdata you need to set __index to a function instead of a table. The function is called with two arguments (the userdata, and the key) whenever you try to access a field on the userdata, and you can query your C object and push the desired result.

如果你打算在同一时间支持方法和属性,它会有点复杂,但基本的方法如下:你使用一个函数 __ index 元方法。此函数可访问方法表(例如通过upvalue或注册表等),并尝试查找该表中的给定键。如果成功,返回该值。如果你没有提供任何东西,你将给定的键与C对象的有效属性名称进行比较,并返回相应的值,如果你得到一个匹配。 (如果你没有得到一个匹配,你可以返回 nil 或者提出一个错误 - 由你决定。)

It gets a little more complicated if you intend to support methods and properties at the same time, but the basic approach is the following: You use a function as __index metamethod. This function has access to a table of methods (e.g. via an upvalue or the registry, etc.) and tries to lookup the given key in that table. If you succeed you return that value. If you come up with nothing, you compare the given key to the valid property names of your C object and return the respective values if you get a match. (If you don't get a match you can return nil or raise an error -- that's up to you.)

以下是此方法的可重用实施(摘自月球工具包):

Here is a reusable implementation of that approach (extracted from the moon toolkit):

static int moon_dispatch( lua_State* L ) {
  lua_CFunction pindex;
  /* try method table first */
  lua_pushvalue( L, 2 ); /* duplicate key */
  lua_rawget( L, lua_upvalueindex( 1 ) );
  if( !lua_isnil( L, -1 ) )
    return 1;
  lua_pop( L, 1 );
  pindex = lua_tocfunction( L, lua_upvalueindex( 2 ) );
  return pindex( L );
}

MOON_API void moon_propindex( lua_State* L, luaL_Reg const methods[],
                              lua_CFunction pindex, int nups ) {
  if( methods != NULL ) {
    luaL_checkstack( L, nups+2, "not enough stack space available" );
    lua_newtable( L );
    for( ; methods->func; ++methods ) {
      int i = 0;
      for( i = 0; i < nups; ++i )
        lua_pushvalue( L, -nups-1 );
      lua_pushcclosure( L, methods->func, nups );
      lua_setfield( L, -2, methods->name );
    }
    if( pindex ) {
      lua_pushcfunction( L, pindex );
      if( nups > 0 ) {
        lua_insert( L, -nups-2 );
        lua_insert( L, -nups-2 );
      }
      lua_pushcclosure( L, moon_dispatch, 2+nups );
    } else if( nups > 0 ) {
      lua_replace( L, -nups-1 );
      lua_pop( L, nups-1 );
    }
  } else if( pindex ) {
    lua_pushcclosure( L, pindex, nups );
  } else {
    lua_pop( L, nups );
    lua_pushnil( L );
  }
}

用法:

/*  [ -nup, +1, e ]  */
void moon_propindex( lua_State* L,
                     luaL_Reg const* methods,
                     lua_CFunction index,
                     int nup );




此函数用于创建__index元字符。如果index是NULL,但方法不是,则创建一个包含方法中所有函数的表,并将其推到堆栈的顶部。如果索引不是NULL,但方法是,索引函数指针被简单地推到堆栈的顶部。如果两者都是非NULL,一个新的C闭包被创建并推送到堆栈,首先尝试查找方法表中的一个键,如果不成功则调用原索引函数。如果两者都为NULL,则nil被推送到堆栈。如果nup非零,给定数量的upvalue从堆栈的顶部弹出并且对所有注册的函数可用。 (如果索引和方法不为NULL,则索引函数在索引1和2处接收两个额外的上值。)此函数用于执行moon_defobject,但也许它对您独立有用。

This function is used for creating an __index metafield. If index is NULL but methods is not, a table containing all the functions in methods is created and pushed to the top of the stack. If index is not NULL, but methods is, the index function pointer is simply pushed to the top of the stack. In case both are non NULL, a new C closure is created and pushed to the stack, which first tries to lookup a key in the methods table, and if unsuccessful then calls the original index function. If both are NULL, nil is pushed to the stack. If nup is non-zero, the given number of upvalues is popped from the top of the stack and made available to all registered functions. (In case index and methods are not NULL, the index function receives two additional upvalues at indices 1 and 2.) This function is used in the implementation of moon_defobject, but maybe it is useful to you independently.

如果你试图在userdata中存储任意的Lua值(就像标题所示) - 你不能。但是,您可以将一个额外的表(称为uservalue)与每个userdata关联,并在其中存储任意值。该方法类似于上面的一个,但是,而不是匹配预定义的属性名称和直接访问C对象,你首先push uservalue表(使用 lua_getuservalue ),然后查找您的字段。

If you try to store arbitrary Lua values in a userdata (like the title suggests) -- you can't. But you can associate an extra table (called "uservalue") with each userdata and store arbitrary values there. The approach is similar to the one above, but instead of matching with predefined property names and accessing the C object directly you first push the uservalue table (using lua_getuservalue) and then lookup your field there.

这篇关于如何在userdata中存储值类型?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆