Вложенные вызовы lua_CFunction
Каков наилучший способ справиться с вложенными вызовами lua_CFunction? Предположим, у меня есть две функции, подобные этой:
static int function2(lua_State *L) {
int i = luaL_checkint(L, 1);
/* do something */
return 1;
};
static int function1(lua_State *L) {
struct udata *u = luaL_checkudata(L, 1, UDATA_METATABLE);
int i = luaL_checkint(L, 2);
/* do something */
/* this does not work, first on call stack is udata, not int */
return function2(L);
};
Вызов функции, как указано выше, не работает. Одним из вариантов является изменение function2()
использовать последний элемент (индекс -1) в стеке, но это не решение вообще function2()
может вызываться из разных мест с разными стеками вызовов. Другим способом было бы заменить return function2(L);
от
lua_pushcfunction(L, function2);
lua_pushvalue(L, 2);
lua_call(L, 1, 1); /* need to know number of results */
Я предполагаю, что это дает function2()
свой стек вызовов, поэтому нет необходимости его модифицировать. Но это решение кажется слишком сложным для функций с большим количеством параметров, поскольку требует дублирования всех их в стеке.
tl; dr: Каков рекомендуемый способ / хороший способ назвать lua_CFunction
из другого?
3 ответа
В function1
вы ожидаете, что в нижней части стека находятся пользовательские данные. Когда вы звоните function2
напрямую LuaState не изменился, и поэтому в нижней части все еще находятся пользовательские данные.
Вы можете успешно позвонить function2
от function1
гарантируя, что целое число находится в индексе 1.
Вы можете сделать это, позвонив lua_insert(L, 1)
который переместит вершину (предполагая индекс 2), в индекс 1.
Вы также можете сделать это, вытолкнув все значения, вернув целое число обратно:
lua_pop(L, lua_gettop(L));
lua_pushnumber(L, i);
return function2(L);
lua_CFunction - не полностью функция Lua. Это просто способ создать Lua функцию / замыкание.
static int function1(lua_State *L) {
....
int top = lua_gettop(L);
lua_pushcfunction(L, function2);
lua_pushvalue(L, 2);
lua_call(L, 1, LUA_MULTRET);
return lua_gettop(L) - 1;
}
Эквивалент Lua
function function1(arg)
return (function(arg) --[[body of f2]] end)(arg)
end
Таким образом, вы каждый раз создаете новую функцию и вызываете ее. Для функции C это вполне нормально, потому что ее не нужно компилировать, а вам не нужно upvalue. Также в Lua 5.2 введена легкая функция для этого. Но если вы хотите эквивалент для
int i = 1
local function function2(arg)
i = i + 1
...
end
function function1(arg)
return function2(arg)
end
Вам нужен способ найти настоящую функцию Lua, например (не проверено)
int f2_ref;
static int function1(lua_State *L) {
...
-- push `function2` on stack
lua_rawgeti(L, LUA_REGISTRYINDEX, f2_ref);
-- as above
}
static int function2(lua_State *L) {
int my_upvalue = lua_tonumber(L, lua_upvalueindex(1));
my_upvalue++;
lua_pushnumber(L, my_upvalue);
lua_replace(L, lua_upvalueindex(1));
...
}
int luaopen_foo(lua_State *L){
-- Here we create instance of Lua function(closure)
lua_pushnumber(L, 1);
lua_pushcclosure(L, function2, 1);
f2_ref = luaL_ref(L, LUA_REGISTRYINDEX);
lua_pushcclosure(L, function1, 0);
return 1;
}
Я бы сказал, что звонить через lua - рекомендуемый способ сделать это, но если вы не хотите делать это по какой-то причине, то предложения Тиммы - правильные.