调用返回表的Lua函数

我知道如何与 Lua 和 C 交互的基础知识,目前我正在尝试在 C++ 中执行以下 Lua 代码:

Func1():Func2().Table1.value1

我想获取 "value2" 的值并在我的 C 程序中使用它。以下是我尝试在 C 中获取该值的代码:

int GetNumber()
{
    int retn = 0;
    g_clientlua.lua_getfield(LUA_REGISTRYINDEX, "Player");
    g_clientlua.lua_getfield(-1, "Func2");
    g_clientlua.lua_getfield(LUA_GLOBALSINDEX, "Func1");
    g_clientlua.lua_call(0, 1);
    g_clientlua.lua_call(1, 1);
    if (g_clientlua.lua_isnil(-1))
        return retn;
    g_clientlua.lua_getfield(-1, "Table1");
    if (g_clientlua.lua_isnil(-1))
        return retn;
    g_clientlua.lua_getfield(-1, "value1");
    if (g_clientlua.lua_isnil(-1))
        return retn;
    retn = (int)g_clientlua.lua_tointeger(-1);
}

g_clientlua 是一个对象,基本上它只允许我调用一个方法,并调用它的 lua_* 函数等效项,填充 lua_state 指针参数,该成员变量是指向 lua 状态的指针。

每次调用这个方法时,它都会抱怨我导致了 lua 堆栈泄漏。为了解决这个问题,我尝试在最后添加了一个 lua_pop(3),但这只是让我的程序崩溃而不报告错误,所以我认为我做错了什么。

有没有人为我提供一点建议?我有点迷失了。我怀疑上面的代码甚至没有正确编写,我应该如何在 C 中编写上述 Lua 调用?

点赞
用户258523
用户258523

你需要在尝试获取 Func2 之前先调用 Func1,因为 Func2 是从 Func1 返回的表中获取而不是全局表中获取的。

然后你需要调用 Func2 并在返回的值中查找 Table1 等等。

你遇到了什么“堆栈泄漏”投诉?如果你直接从C中调用此函数,那么是的,你需要确保你放在lua堆栈上的任何东西(不是为了调用者等消费)在返回之前从lua堆栈中弹出。

2013-07-16 05:57:38
用户234175
用户234175

GetNumber函数并没有完全和你要实现的lua片段一样。具体来说,GetNumber从注册表获取“Func2”的值,而你的lua片段是从Func1()返回的表中获取“Func2”的值。除非你确定registry.Player.Func2==Func1().Func2始终为真,否则你的C++版本将不会有相同的行为。

让我们把Func1():Func2().Table1.value1分解成更具体的步骤,以帮助C语言的翻译:

  1. 获取与_G.Func1关联的函数
  2. 调用该函数并返回一个表
  3. 从步骤2返回的表中获取与“Func2”关联的函数
  4. 调用该函数,并将步骤2中的表作为参数。以另一个表作为结果返回

我发现在执行操作时,在侧面注释中跟踪栈内的内容很有用:

int GetNumber()
{
    // Func1()
    gclientlua.lua_getfield(LUA_GLOBALSINDEX, "Func1");     // Func1
    g_clientlua.lua_call(0, 1);                             // {}

    // Func2( {} )
    g_clientlua.lua_getfield(-1, "Func2");                  // {}, Func2
    g_clientlua.lua_insert(-2);                             // Func2, {}
    g_clientlua.lua_call(1, 1);                             // {}

    if( g_clientlua.lua_type(-1) != LUA_TTABLE )
    {
      g_clientlua.lua_pop(1);
      return 0;
    }

    // {}.Table1
    g_clientlua.lua_getfield(-1, "Table1");                 // {}, {}(Table1)
    if( g_clientlua.lua_type(-1) != LUA_TTABLE )
    {
      g_clientlua.lua_pop(2);
      return 0;
    }

    // tonumber( Table1.value1 )
    g_clientlua.lua_getfield(-1, "value1");                 // {}, {}(Table1), value1
    int retn = g_clientlua.lua_tointeger(-1);
    g_clientlua.lua_pop(3);
    return retn;
}

请注意,GetNumber在返回之前弹出它放在堆栈中的所有参数。这确保了GetNumber离开lua堆栈的方式与它发现的一样。如果你使用C ++,可能可以通过RAII自动化这个过程。

2013-07-17 05:41:08