调用返回表格的lua函数

4

我知道如何与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);
}

客户端lua是一个对象,可以让我调用一个方法,该方法调用它的lua_*函数等价物,并将指向lua状态的成员变量指针参数填充到lua_state指针参数中。但每次调用时都会报告我导致了lua堆栈泄漏。为解决这个问题,我尝试在末尾添加了一个lua_pop(3),但结果程序崩溃且没有报错,因此我认为自己做错了什么。有人能给我一些建议吗?我有点迷茫。我怀疑上述代码甚至没有正确编写,那么我应该如何在C语言中编写上述lua调用呢?
2个回答

2

在尝试获取Func2之前,您需要调用Func1,因为Func2来自Func1返回的表(而不是全局表)。

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

您收到了什么“堆栈泄漏”投诉?如果直接从C调用此函数,则需要确保在返回之前从lua堆栈中弹出任何放置在其中的内容(而不是供调用者等使用)。


我知道,但问题是我不知道该弹出什么,不该弹出什么。我不知道在那个调用中有哪些东西会留在堆栈上等待我弹出。 - haze
2
我建议您阅读Lua API文档,因为它记录了每个函数的堆栈变化。一般来说,lua_get会推送一个东西,lua_to/lua_is*是堆栈中性的,而lua_call的行为取决于您如何调用它。 - Etan Reisner

0

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自动化此过程。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接