如何将Lua函数传递给C函数并执行Lua函数多次?

6
我想做的是创建一个函数,可以遍历一些对象并为每个函数调用一个函数。我使用的是BlitzMax而不是C,但这是次要的,因为它有Lua的C函数的完整包装器。Lua有一个lua_pushcfunction()命令,但它的lua_pushfunction()命令在哪里?调用具有名称的函数非常容易,但如何调用作为参数传递的函数呢?
类似于:
ForEach( PlanetList, function (planet)
    if(planet.exists == true) then
        Planet_Count = Planet_Count + 1
    end
end )

通常你只需要使用"lua_getglobal(L,name)",它会将Lua函数放置在堆栈上,但如何从参数中获取它呢?
编辑
我回去试了一下之前找到的这个问题中的"luaL_ref()"。我正在使用"luaL_ref()"将函数值从堆栈顶部弹出并放入临时寄存器中,我使用从"luaL_ref()"返回的值来使用"lua_rawgeti()"获取列表中的每个项目。然后,在列表完成后,使用"luaL_unref()"来释放该寄存器。

4
请将您的解决方案提取为答案并接受它。 - Alexander Gladysh
2个回答

6

我自己也是新手,曾有同样的疑问,希望能得到满意的答案。但个人认为至今无令人满意的解答。因此我决定自己写一篇,虽然这个问题可能永远不会关闭。希望这能帮助到其他处境相似的人。

main.c

#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>

/* this keeps our Lua reference to the Lua function */
int callback_reference = 0;

/* this is called by Lua to register its function */
int lua_registerCallback( lua_State *L ) {

  /* store the reference to the Lua function in a variable to be used later */
  callback_reference = luaL_ref( L, LUA_REGISTRYINDEX );

  return 0;
}

/* calls our Lua callback function and resets the callback reference */
void call_callback( lua_State *L ) {

  /* push the callback onto the stack using the Lua reference we */
  /*  stored in the registry */
  lua_rawgeti( L, LUA_REGISTRYINDEX, callback_reference );

  /* duplicate the value on the stack */
  /* NOTE: This is unnecessary, but it shows how you keep the */
  /*  callback for later */
  lua_pushvalue( L, 1 );

  /* call the callback */
  /* NOTE: This is using the one we duplicated with lua_pushvalue */
  if ( 0 != lua_pcall( L, 0, 0, 0 ) ) {
    printf("Failed to call the callback!\n %s\n", lua_tostring( L, -1 ) );
    return;
  }

  /* get a new reference to the Lua function and store it again */
  /* NOTE: This is only used in conjunction with the lua_pushvalue */
  /*  above and can be removed if you remove that */
  callback_reference = luaL_ref( L, LUA_REGISTRYINDEX );
}

int main( void ) {

  /* set up Lua */
  lua_State *L = lua_open();
  luaL_openlibs( L );

  /* register the lua_registerCallback function as */
  /*  "RegisterCallback" so it can be called by Lua */
  lua_pushcfunction( L, lua_registerCallback );
  lua_setglobal( L, "RegisterCallback" );

  /* run our Lua file */
  if ( 0 != luaL_dofile( L, "callback.lua" ) ) {
    printf("Failed to load calback.lua!\n %s",
      lua_tostring( L, -1 ) );
    lua_close( L );
    return 1;
  }

  /* call the callback */
  call_callback( L );

  /* call the callback again if you want (because we restored */
  /*  the Lua function reference) */
  call_callback( L );

  /* remove the reference to the callback */
  /* NOTE: This is also unnecessary if you didn't re-add the */
  /*  function to the registry */
  luaL_unref( L, LUA_REGISTRYINDEX, callback_reference );

  /* uninitialize Lua */
  lua_close( L );

  return 0;
}

callback.lua

function MyCallback()
  print("Hello World!")
end

RegisterCallback( MyCallback )

1
在我的测试中,你需要移除 lua_pushvalue( L, 1 ); 才能让这段代码正常工作,否则你可能会遇到 Failed to call the callback! 错误。 - min
经过更多的测试,我发现这个实现在异步程序中不起作用,因为当你调用回调函数时,没有办法获取有效的lua_State。我还尝试保存lua_State,但是出现了访问冲突。 - min

3

当您在堆栈上有函数时,请使用lua_pushvalue来复制它。

更新:每次想要调用函数时,您需要调用lua_pushvalue(),因为实际上使用lua_pcall()或lua_call()调用函数将从堆栈中弹出该函数。


那样做可行,但只能循环一次。:S 我想我已经找到了答案,我会更新第一个帖子。 - Galaxy613

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