5

我正在尝试创建一个名为 Dfetch() 的 C 函数,该函数在 Lua 中注册为 fetch()。我正在寻找它是分层的,这样我就可以调用 dog.beagle.fetch() 作为 Lua 的函数。它只是有助于更好地组织代码。下面是我所拥有的,但它没有调用我的 C 函数。如果我只做全局而不是子表,则调用 C 函数。我是 Lua 的新手,所以我认为我只是设置了错误的表格。

void myregister(lua_State *L, const char *libname, const char *sublibname, const luaL_Reg *l) 
{ 
    luaL_newmetatable(L, libname); 
    lua_newtable(L); luaL_setfuncs(L,l,0); 
    lua_pushvalue(L,-1); 
    if(sublibname != NULL) 
    { 
        lua_newtable(L); 
        lua_setfield(L, -2, sublibname); 
    } 
    lua_setglobal(L, libname);
}

luaL_Reg fidofuncModule[] = { {"fetch", Dfetch}, {NULL, NULL}};

在我的 main() 中,我调用以下内容:

lua_State * execContext = luaL_newstate();
//adding lua basic library
luaL_openlibs(execContext);

myregister(execContext, "dog", "beagle", fidofuncModule);


strcpy(buff, "dog.beagle.fetch();");
errorcode = luaL_loadbuffer(execContext, buff, strlen(buff), "line");
errorcode = lua_pcall(execContext, 0, 0, 0);

if (errorcode)
{
  printf("%s", lua_tostring(execContext, -1));
  lua_pop(execContext, 1);  /* pop error message from the stack */
}
//cleaning house
lua_close(execContext);

谢谢,蒂姆

4

3 回答 3

3

问题

好的,让我们来看看这个函数和堆栈。

luaL_newmetatable(L, libname); 

好的,堆栈现在包含来自元表注册表的表:

-1: table<libname>{possibly empty}

下一个:

lua_newtable(L);

堆栈现在包含:

-1: table<new>{empty}
-2: table<libname>{possibly empty}

下一个:

luaL_setfuncs(L,l,0); 

不改变堆栈。但它确实在表中设置了一堆函数。

-1: table<new>{bunch of functions}
-2: table<libname>{possibly empty}

下一个:

lua_pushvalue(L,-1); 

这会复制堆栈顶部的值。那是我们的表,有一堆函数:

-1: table<new>{bunch of functions}
-2: table<new>{bunch of functions}
-3: table<libname>{possibly empty}

下一个:

if(sublibname != NULL) 
{ 
    lua_newtable(L); 

这会在堆栈上创建一个空的新表:

-1: table<new2>
-2: table<new>{bunch of functions}
-3: table<new>{bunch of functions}
-4: table<libname>{possibly empty}

下一个:

    lua_setfield(L, -2, sublibname); 

如文档中所述,此函数将值设置到给定表键名的表中。该值是堆栈顶部的值,但它放入的表是索引

所以你只是这样做了:

-1: table<new>{bunch of functions, sublibname=table<new2>}
-2: table<new>{bunch of functions, sublibname=table<new2>}
-3: table<libname>{possibly empty}

我很确定这不是你想要的。当我们继续时,我将讨论如何解决这个问题。

下一个:

}

lua_setglobal(L, libname);

这将获取堆栈顶部并将其粘贴在全局表中,将其从堆栈顶部弹出。

所以堆栈现在看起来像这样:

-1: table<new>{bunch of functions, sublibname=table<new2>{empty}}
-2: table<libname>{possibly empty}

全局表现在有:

_G[libname] = table<new>{bunch of functions, sublibname=table<new2>{empty}}

因此,您不仅使堆栈不平衡(推送多于弹出),而且您没有得到您真正想要的东西。另外,注册表中的元表包含……什么都没有。

解决方案

所以让我们解决这个问题。让我们正确地做到这一点。

你试图做的几乎所有事情都是错误的。首先,做子表的唯一原因是这样的代码可以工作:

myregister(execContext, "dog", "beagle", fidofuncModule);
myregister(execContext, "dog", "dane", danefuncModule);

这样,您可以调用dog.beagledog.dane。好吧,要做到这一点,myregister必须检查全局表以查看是否已经有一个dog表。如果有,它需要在其中存储它的东西,如果没有,它需要创建它。所以你的整个算法有点坏了。

另外,大概你想要dog.beagle并且dog.dane两者都有自己的fetch功能。好吧,注册表只有一个地方可以放一张dog桌子,所以如果你只libname用你的luaL_newmetatable电话,他们会在彼此的桌子上跺脚。

这是将如何解决它。我不知道这是否适用于您正在做的事情,但这就是我要做的。

首先,忘记整个newmetatable废话;我们总是根据新表格工作。因此,我们将创建内部表并在其上设置函数:

lua_newtable(L);
luaL_setfuncs(L,l,0);

所以堆栈看起来像:

-1: table<new>{bunch of functions}

下一步,如果我们没有子库名称,那么我们应该直接将其设置到全局变量下libname并返回:

if(!sublibname)
{
    lua_setglobal(L, libname);
    return;
}

这将从堆栈中弹出一个值并将其设置在该位置。

由于我们确实有一个子库名称,因此我们需要将此表存储在主表中。如果 中已经有一个表_G[libname],那么我们就得到那个表。否则,我们创建一个新表并将其粘贴到_G[libname].

lua_getglobal(L, libname);
if(lua_isnil(L, -1))
{
  /*No table. Must create it and put it into the global*/
  lua_newtable(L);
  lua_pushvalue(L, -1); /*duplicate it on the stack*/
  lua_setglobal(L, libname); /*pushes duplicate*/
}

此时,我们的堆栈包含:

-1: table<libname>{possibly empty}
-2: table<new>{bunch of functions}

然后,我们将创建的表粘贴到该表中,sublibname用作字段:

lua_pushvalue(L, -2); /*duplicates our created table*/
lua_setfield(L, -2, sublibname);

现在堆栈包含:

-1: table<libname>{stuff, sublibname=table<new>{bunch of functions}}
-2: table<new>{bunch of functions}

由于表已经在全局表中(我们要么从那里得到它,要么在我们创建它时将它存储在那里),我们就完成了。所以清理堆栈:

lua_pop(L, 2); /*balance the stack. Remove our junk from it*/
于 2012-11-13T19:46:42.327 回答
2
void myregister(lua_State *L, const char *libname, const char *sublibname, const luaL_Reg *lib) 
{ 
    // create 'libname' table
    lua_newtable(L); 

    // no sublib: just import our library functions directly into lib and we're done
    if (sublibname == NULL) 
    { 
        luaL_setfuncs(L, lib, 0); 
    } 
    // sublib: create a table for it, import functions to it, add to parent lib
    else
    {
        lua_newtable(L); 
        luaL_setfuncs(L, lib, 0); 
        lua_setfield(L, -2, sublibname); 
    }

    lua_setglobal(L, libname);
}
于 2012-11-13T19:48:44.753 回答
0

fetch正在注册libname中,而不是sublibname中。要确认,print(dog.fetch)buff在通话前添加。

试试这个:

void myregister(lua_State *L, const char *libname, const char *sublibname, const luaL_Reg *l) 
{ 
    lua_newtable(L);
    lua_pushvalue(L,-1); 
    lua_setglobal(L, libname);
    if(sublibname != NULL) 
    { 
        lua_newtable(L); 
        lua_pushvalue(L,-1); 
        lua_setfield(L, -3, sublibname); 
    } 
    luaL_setfuncs(L,l,0); 
}
于 2012-11-13T19:42:06.493 回答