簡體   English   中英

如何在用戶數據中存儲值類型?

[英]How to store a value type in a userdata?

這篇SO文章是同一回事,但是答案無濟於事,因為答案在Lua中,而問題與C-API有關。 所以我再次詢問。 希望其他人將從這個問題中受益。

我實際上有2個問題(我無法使用y和z來工作,也無法使用helloworld()來工作)

我試圖做到這一點:

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

其中x是用戶數據。 我一直在attempt to index a userdata value

我知道“用戶數據沒有元表就無法索引,因為它是C / C ++數據

在我的C代碼中,我做這樣的事情來嘗試包裝對象。

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()) ,我會得到相同的錯誤: attempt to index a userdata value

在我的代碼中,我都不知道如何正確附加值類型yz

首先,對於helloworld您的代碼有效:

/* 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() )

輸出為:

你好,世界!

為了訪問用戶數據上的屬性,您需要將__index設置為函數而不是表。 每當您嘗試訪問用戶數據上的字段時,都會使用兩個參數(用戶數據和鍵)來調用該函數,並且您可以查詢C對象並推送所需的結果。

如果打算同時支持方法和屬性,它將變得更加復雜,但是基本方法如下:將函數用作__index元方法。 該函數可以訪問方法表(例如,通過上值或注冊表等),並嘗試在該表中查找給定鍵。 如果成功,則返回該值。 如果什么都不做,則將給定的鍵與C對象的有效屬性名稱進行比較,如果得到匹配,則返回各自的值。 (如果沒有找到匹配項,則可以返回nil或引發錯誤-由您自己決定。)

這是該方法的可重用實現(摘自moon工具箱 ):

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但方法不是,則創建包含方法中所有功能的表並將其推入堆棧的頂部。 如果index不是NULL,而是method,則將index函數指針簡單地推到棧頂。 如果兩者都不為NULL,則創建一個新的C閉包並將其推入堆棧,該閉包首先嘗試在方法表中查找鍵,如果不成功,則調用原始索引函數。 如果兩者均為NULL,則將nil壓入堆棧。 如果nup不為零,則從堆棧頂部彈出給定數量的upvalue,並使其可用於所有已注冊的函數。 (如果索引和方法不為NULL,則索引函數將在索引1和2處接收兩個額外的上值。)此函數用於moon_defobject的實現中,但也許對您獨立有用。

如果您嘗試在用戶數據中存儲任意Lua值(如標題所示),則不能。 但是您可以將一個額外的表(稱為“ uservalue”)與每個userdata關聯,並在其中存儲任意值。 該方法與上面的方法類似,但是不是先匹配預定義的屬性名稱並直接訪問C對象,而是先推送uservalue表(使用lua_getuservalue ),然后在此處查找字段。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM