处理嵌套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
的推荐方式/好方法是什么?
答案 0 :(得分:3)
在function1
中,您希望堆栈的底部是用户数据。
直接调用function2
时,LuaState没有更改,因此底部仍然是用户数据。
您可以通过确保整数位于索引1,从function2
成功呼叫function1
。
您可以通过调用lua_insert(L, 1)
来执行此操作,该lua_pop(L, lua_gettop(L));
lua_pushnumber(L, i);
return function2(L);
会将顶部(假设索引2)移至索引1。
你也可以通过弹出所有值来重新推动整数:
{{1}}
答案 1 :(得分:1)
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;
}
答案 2 :(得分:0)
我会说通过lua 调用它是推荐的方法,但如果你不想因为某些原因那样做,那么Timma的建议是正确的。