[英]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
在我的代碼中,我都不知道如何正確附加值類型y
或z
。
首先,對於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.