Эта ТАКИЕ статьи это то же самое, но ответ бесполезен, потому что ответ был на 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
,
Во-первых, для 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
), а затем найдите свое поле там.