【问题标题】:Lua stack issueLua堆栈问题
【发布时间】:2010-08-22 10:46:03
【问题描述】:

我真的无法制作一个简短但描述性的标题来解释我的问题,很抱歉。

我正在从 c++ 调用一个名为 hook.Call(event, ...) 的 lua 函数。它调用所有使用 hook.Add(event, unique_name, function) 添加的函数

问题是,当我在挂钩中调用 print(...) 函数时,它不会打印您期望它打印的内容,因为调用挂钩的堆栈仍然存在。所以它从那个堆栈打印。 而且我无法移除堆栈,因为那样我将无法从钩子中获取返回值。

钩子调用如下所示:

int CGame::Update(bool haveFocus, unsigned int updateFlags)
{

    hook::StartCall("PreGameUpdate");
        hook::PushInteger(haveFocus);
        hook::PushInteger(updateFlags);
    hook::CallReturn(1, 2); //Calls hook.Call("PreGameUpdate", haveFocus, updateFlags) here 

        //The first argument is the amount of values to return to C++
        //The second argument is how many values that were pushed onto the stack (maybe I can monitor that?)

        if(hook::IsBoolean(1) && hook::GetBoolean(1) == false)
            return false; //skip the rest of the code if we return false in the Pre hook

    hook::End();

    //rest of the code in CGame::Update() here

}

我正在考虑打印下一帧,但这听起来很糟糕,我什至不知道该怎么做。

钩子函数

namespace hook
{
    void StartCall(string hookname)
    { lua_State *L = LuaJIT::GetState();

        //Remove any previous stack (just in case?)
        //Stack is now: nil
        lua_settop(L, 0);

        //Get the "hook" global and check if it exists
        //stack is now: hook
        lua_getglobal(L, "hook");
            if (!lua_istable(L, -1))            
                return;

        //Get the function "Call" and check if it exists
        //Stack is now: hook.Call()
        lua_getfield(L, -1, "Call");
            if (!lua_isfunction(L, -1))
                return;

        //Remove the "hook" table from the stack leaving only the Call function left
        //Stack is now: Call()
        lua_remove(L, 1);

        //Push the hookname onto the stack
        //Stack is now: Call(hookname)
        lua_pushstring(L, hookname);
    }

    void CallReturn(int returns, int args)
    { lua_State *L = LuaJIT::GetState();

        //PrintStack("PRE PCALL"); 
        /* When printing the stack, this is the output:
            ===========PRE PCALL=================START

                1: 
            function: 2116D588

                2: 
            PreGameUpdate

                3: 
            1.000000

                4: 
            0.000000

            ===========PRE PCALL=================END
        */

        //Check if the first value is a function and if the stack is valid
        if (!lua_isfunction(L, 1) || lua_gettop(L) == 0)
        {
            PrintStack("NO FUNCTION IN STACK");
            return;
        }

        //pcall "Call" from the stack and check if it worked
        //Stack is now: pcall(Call(hookname, ...))
        int status = lua_pcall(L, args + 1, returns, 0);

        //Check if it errored
        if(status != 0)
        {
            //Print to debug output if it errored
            PrintStack("STACK"); 
            Msg("PCALL ERROR[%s]: %s", lua_tostring(L, 1), lua_tostring(L, -1));
        }
        //PrintStack("POST PCALL"); 
    }

    void End()
    {   lua_State *L = LuaJIT::GetState();

        //Remove the stack again
        //Stack is now: nil
        lua_settop(L, 0);
    }

    void EndNoReturn(int args)
    {
        CallReturn(0, args);
        End();
    }

    void StartCallNoPush(string hookname, int returns)
    {
        StartCall(hookname);
        CallReturn(0, returns);
    }

    void CallSimple(string hookname)
    {
        StartCall(hookname);
        CallReturn(0, 0);
        End();
    }

    void PushBoolean(bool res) 
    { lua_State *L = LuaJIT::GetState();        

        int test = toint(res);

        lua_pushboolean(L, test);
    }
    bool GetBoolean(int idx)
    { lua_State *L = LuaJIT::GetState();    

        int res = lua_toboolean(L, idx);
        lua_pop(L, 1);
        return tobool(res);
    }
    int IsBoolean(int idx)
    { lua_State *L = LuaJIT::GetState();

        int res = lua_isboolean(L, idx);
        lua_pop(L, 1);
        return res;
    }

    //The rest of the code is just like the three functions above but for different types
}

打印功能

int print(lua_State *L)
{
    //PrintStack("PRINT PRE");
    int n = lua_gettop(L);  /* number of arguments */
    int i;
    lua_getglobal(L, "tostring");
    for (i=1; i<=n; i++) {
        const char *s;
        lua_pushvalue(L, -1);  /* function to be called */
        lua_pushvalue(L, i);   /* value to print */
        lua_call(L, 1, 1);
        s = lua_tostring(L, -1);  /* get result */
        if (s == NULL)
            return luaL_error(L, LUA_QL("tostring") " must return a string to "
                            LUA_QL("print"));
        if (i>1) CryLogAlways("\t");
            CryLogAlways(s);
        lua_pop(L, 1);  /* pop result */
    }
    CryLogAlways("\n");
    //PrintStack("PRINT POST");
    return 0;
}

我没有充分利用打印功能。我是从我朋友的代码中获取的,所以它不像那些钩子函数那样被注释掉。当未在挂钩中调用时,打印确实有效。

所以 print 的问题在于它会打印钩子堆栈中的所有内容,因为它是在我删除堆栈之前调用的。

我还发现推送和弹出非常令人困惑,因此它确实有助于注释代码,例如在钩子调用函数中显示当前堆栈是什么。

我猜整个问题是 c++ 中的钩子函数的设计缺陷,但我真的不知道该怎么做。

【问题讨论】:

  • 您说打印功能没有按照您的预期执行,但您从未说过您希望它执行的操作。看起来它应该打印堆栈的全部内容,并且根据您的问题,这就是它的作用。顺便说一句,print 的末尾似乎缺少一个 pop(tostring 的值将保留在堆栈上)。
  • 是的,我认为我的问题中缺少一些东西: print 的问题是它打印了钩子堆栈中的所有内容,因为它在我删除堆栈之前被调用。我对 c++ 和 lua api 很陌生;当我完成某些事情时,我应该删除堆栈吗?我正在使用 lua_settop(L, 0) 在 hook::End() 中删除它 通常人们使用 lua_pop 从堆栈中删除一个值。他们不应该全部删除吗?我会在最后添加 lua_pop,但我认为它仍然不能解决我的问题。
  • 您能否详细说明您希望 print() 函数完成什么。正如用户 interjay 指出的那样,它目前的形式是从堆栈中检索内容。

标签: lua stack


【解决方案1】:

我在 int print 的底部弹出了堆栈的字符串作为评论中提到的 interjay,它的工作方式与现在一样。

很抱歉描述性不够。

【讨论】:

  • 我建议你接受你自己的答案。否则,此问题会在列表中显示为“未回答”。
猜你喜欢
  • 2015-11-05
  • 1970-01-01
  • 2023-03-04
  • 2021-04-13
  • 2015-12-18
  • 2012-05-15
  • 2012-07-10
  • 1970-01-01
  • 2012-08-06
相关资源
最近更新 更多