简体   繁体   English

尝试使用嵌套表调用Lua中的函数

[英]Trying to call a function in Lua with nested tables

I am trying to create a C function called Dfetch() that is registered in Lua as fetch(). 我正在尝试创建一个名为Dfetch()的C函数,它在Lua中注册为fetch()。 I am looking for it to be tiered such that I can call dog.beagle.fetch() as the function from Lua. 我正在寻找分层,以便我可以将dog.beagle.fetch()称为Lua的函数。 It just helps with the organization of the code better. 它只是有助于更好地组织代码。 Below is what I have, but it is not calling my C function. 下面是我的,但它不是调用我的C函数。 If I just do the global and not the subtable, the C function gets called. 如果我只是执行全局而不是子表,则调用C函数。 I am new to Lua, so I think I am just setting up the tables wrong. 我是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}};

In my main(), I call the following: 在我的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);

Thanks, Tim 蒂姆,谢谢

The Problem(s) 问题

OK, let's walk through this function and the stack. 好的,让我们来看看这个函数和堆栈。

luaL_newmetatable(L, libname); 

OK, the stack now contains a table from the metatable registry: 好的,堆栈现在包含metatable注册表中的表:

-1: table<libname>{possibly empty}

Next: 下一个:

lua_newtable(L);

The stack now contains: 堆栈现在包含:

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

Next: 下一个:

luaL_setfuncs(L,l,0); 

Doesn't change the stack. 不会改变堆栈。 But it does set a bunch of functions into the table. 但它确实在表格中设置了许多功能。

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

Next: 下一个:

lua_pushvalue(L,-1); 

This copies the value on top of the stack. 这会将值复制到堆栈顶部。 That's our table with a bunch of functions: 那是我们的表,有很多功能:

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

Next: 下一个:

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

This creates a new table on the stack that's empty: 这会在堆栈上创建一个空的新表:

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

Next: 下一个:

    lua_setfield(L, -2, sublibname); 

This function, as stated in the documentation , sets a value into a table at the given table key name. 如文档中所述 ,此函数将值设置为给定表键名称的表。 The value is the value at the top of the stack, but the table it puts it in is the index . 该值是堆栈顶部的值,但它放入的表是索引

So you just did this: 所以你刚才这样做了:

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

I'm pretty sure that's not what you wanted. 我很确定这不是你想要的。 I'll get to how to fix that when we continue. 当我们继续时,我会谈到如何解决这个问题。

Next: 下一个:

}

lua_setglobal(L, libname);

This takes the top of the stack and sticks it in the global table, poping it off the top of the stack. 它占据堆栈顶部并将其粘贴到全局表中,从堆栈顶部弹出。

So the stack now looks like this: 所以堆栈现在看起来像这样:

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

And the global table now has: 全球表现在有:

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

So not only have you unbalanced the stack (more pushes than pops), you didn't get what you actually wanted. 因此,不仅你的堆栈不平衡(比弹出更多的推动),你没有得到你真正想要的东西。 Plus, your metatable from the registry contains... nothing at all. 另外,来自注册表的metatable包含......什么都没有。

The Solution 解决方案

So let's fix this. 所以让我们解决这个问题。 And let's do it properly. 让我们正确地做到这一点。

Pretty much everything about what you tried to do is wrong. 几乎所有关于你试图做的事情都是错误的。 First, the only reason to do the subtable thing is so code like this will work: 首先,执行子表单的事情的唯一原因是这样的代码将起作用:

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

This way, you can call dog.beagle and dog.dane . 这样,你可以调用dog.beagledog.dane Well, to do that, myregister has to check the global table to see if there's already a dog table. 好吧,要做到这一点, myregister必须检查全局表,看看是否已经有一个dog表。 If there is, it needs to store its stuff in there, and if not, it needs to create it. 如果有,它需要在那里存储它的东西,如果没有,它需要创建它。 So your whole algorithm is kinda broken. 所以你的整个算法都有点破碎了。

Also, presumably you want dog.beagle and dog.dane to both have their own fetch function. 另外,大概你想要dog.beagledog.dane都有自己的fetch功能。 Well, the registry only has one place for a dog table, so if you use just libname for your luaL_newmetatable call, they'll be stomping on each others tables. 好吧,注册表只有一个dog桌的位置,所以如果你只使用libname作为你的luaL_newmetatable调用,他们就会在彼此的桌子上踩踏。

Here's how I would solve it. 这是如何解决它。 I have no idea if this works for what you're doing, but this is what I'd do. 我不知道这是否适用于你正在做的事情,但这就是我要做的。

First, forget the whole newmetatable nonsense; 首先,忘记整个newmetatable胡言乱语; we work based on new tables, always. 我们总是以新表为基础工作。 So we'll create the inner table and set functions onto it: 所以我们将创建内部表并在其上设置函数:

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

So the stack looks like: 所以堆栈看起来像:

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

Next step, if we don't have a sub-library name, then we should set this directly into the global variable under libname and return: 下一步,如果我们没有子库名,那么我们应该直接将它设置为libname下的全局变量并返回:

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

That will pop the one value from the stack and set it in that location. 这将从堆栈中弹出一个值并将其设置在该位置。

Since we do have a sub-library name, we need to store this table in the main table. 由于我们有一个子库名称,我们需要将该表存储在主表中。 If there's already a table in _G[libname] , then we get that table. 如果_G[libname]已经有一个表,那么我们就得到那个表。 Otherwise, we create a new table and stick it into _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*/
}

At this point, our stack contains: 此时,我们的堆栈包含:

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

We then stick our created table into that one, using sublibname as the field: 然后我们将创建的表粘贴到那个表中,使用sublibname作为字段:

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

Now the stack contains: 现在堆栈包含:

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

Since table is already in the global table (we either got it from there, or stored it there when we created it), we're done. 由于表已经在全局表中(我们要么从那里得到它,要么在我们创建它时将它存储在那里),我们就完成了。 So clean up the stack: 所以清理堆栈:

lua_pop(L, 2); /*balance the stack. Remove our junk from it*/
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);
}

fetch is being registered into libname , not into sublibname . fetch正在注册到libname ,而不是注册到sublibname To confirm, add print(dog.fetch) to buff before the call. 要确认,请在通话前将print(dog.fetch)添加到buff

Try this: 尝试这个:

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); 
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM