Как сохранить тип значения в пользовательских данных?

Эта ТАКИЕ статьи это то же самое, но ответ бесполезен, потому что ответ был на Lua, а вопрос был о C-API. Поэтому я снова спрашиваю. Надеюсь, другие извлекут выгоду из этого вопроса.

На самом деле у меня 2 проблемы (я не могу заставить работать работу по оси Y и я не могу заставить работать 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,

1

Решение

Во-первых, для 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 или поднять ошибку — решать вам.)

Вот многократная реализация этого подхода (извлечено из лунный инструментарий):

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, а методы есть, указатель на функцию index просто помещается в верхнюю часть стека. В случае, если оба значения не равны NULL, создается новое замыкание C и помещается в стек, который сначала пытается найти ключ в таблице методов, а в случае неудачи вызывает исходную функцию индекса. Если оба имеют значение NULL, nil помещается в стек. Если nup не равен нулю, заданное число повышений выталкивается из верхней части стека и становится доступным для всех зарегистрированных функций. (Если index и методы не равны NULL, функция index получает два дополнительных значения в индексах 1 и 2.) Эта функция используется в реализации moon_defobject, но, возможно, она будет полезна вам независимо.

Если вы попытаетесь сохранить произвольные значения Lua в пользовательских данных (как предполагает заголовок) — вы не сможете. Но вы можете связать дополнительную таблицу (называемую «uservalue») с каждым userdata и хранить там произвольные значения. Подход аналогичен приведенному выше, но вместо сопоставления с предварительно определенными именами свойств и прямого доступа к объекту C вы сначала выдвигаете таблицу пользовательских значений (используя lua_getuservalue), а затем найдите свое поле там.

4

Другие решения


По вопросам рекламы [email protected]