[英]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 蒂姆,谢谢
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包含......什么都没有。
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.beagle
和dog.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.beagle
和dog.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.