我正在为我们的应用程序编写一个 lua (5.1) 扩展,允许我们的客户在没有我们支持的情况下使用更多屏幕来扩展它。
总的来说,这工作得很好,在十几个包装器的帮助下甚至非常舒服,但现在我遇到了以下情况:
我有两个用户数据对象,一个对象 Timer 和一个对象 Window。 用户只需定义其成员 OnTimer 和 OnSizeChanged 即可将事件“附加”到它们。
这仍然非常有效: mainLoop (C++) -> 检查所有计时器 (C++)-> 附加脚本对象? (C++),然后:
// get ud by reference / stack: +1 / 1
lua_rawgeti(mState, LUA_REGISTRYINDEX, miReferenceId);
lua_getfenv(mState, -1); // get attached table / +1 / 2 total
lua_getfield(mState, -1, functionName.ToChar()); // +1 / 3 total
if (!lua_isfunction(mState, -1))
{
...
}
lua_remove(mState, -2); // remove table / -1 / 2 total
lua_remove(mState, -2); // remove ud / -1 / 1 total, just function remaining
// ( .. user data still pushed at this point ..)
lua_pcall(mState, 1, 0, 0);
因此,在以下场景中,一切仍然完美(在启动调用之前和之后堆栈肯定为 0):
function OnTimer(Self)
Log("Some text") // Log calls C++ luaLog with 1 argument
end
myTimer = timer.new()
myTimer.OnTimer=OnTimer;
如果 lua 脚本看起来像这样:
timer = timer.new()
window = window.new()
function OnTimer(Self)
window:SetSize(323.5,234.5)
end
function OnSizeChanged(Self,NewWidth,NewHeight)
Log("Sized changed")
end
timer.OnTimer = OnTimer
window.OnSizeChanged = OnSizeChanged
那么 C++ 中的调用堆栈将是:
timer::HandleTimer (C++) ->
push "OnTimer" function ->
push timer ud ->
pcall (L,1) -> .. (Lua)
static int luaChangeSize(lua_State *L) (back to C++) ->
Window::SetSize ->
The window sees "oooooooh, an event handler has been assigned" ->
push "OnSizeChanged" function, window ud, x, y ->
pcall(L,3,0,0) -> .. (Lua) ->
int luaLog(lua_state* L) (back to C++ again)
当然,在调用OnSizeChanged时,堆栈仍然包含之前luaChangeSize回调的内容,并且不为空。
我以为我可以通过在调用 Window::SetSize 之前弹出 luaChangeSize 的所有参数并在之后恢复它们来简单地清理堆栈,但这不起作用。结果有点随机,具体取决于调用堆栈的星座,从“无法调用数字”到再次随机调用堆栈上的前一个函数。 (所有调用前后gettop肯定为0)。
那么:如何“备份”当前堆栈并在之后恢复它,就像 lua 在 C++ -> Lua -> C++ 星座中那样?
非常感谢。
最佳答案
备份和恢复堆栈的概念似乎是错误的。难道你不能让堆栈保持原样,让新的调用在现有堆栈之上工作吗?确保所有内容都使用相对于顶部索引而不是绝对索引来访问堆栈上的项目。
关于c++ - 如何从一个lua函数调用另一个lua函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30047467/