【问题标题】:How do you pass a Lua Function to a C Function and execute the Lua Function Several Times?如何将 Lua 函数传递给 C 函数并多次执行 Lua 函数?
【发布时间】:2025-12-30 08:15:16
【问题描述】:

我想要做的是创建一个函数,它将遍历一些对象并为每个函数调用一个函数。我使用的是 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 函数很好地放在堆栈上,但是你如何从一个参数中得到它呢?

编辑

我返回并实际尝试使用来自this question I found earlierluaL_ref()。我正在做的是使用 luaL_ref() 从堆栈顶部弹出函数值并将其放入临时寄存器中,我使用从 luaL_ref() 返回的值对列表中的每个项目使用 lua_rawgeti() .然后在列表完成后使用luaL_unref()释放该寄存器。

【问题讨论】:

  • 请将您的解决方案提取到答案并接受它。

标签: function lua stack push arguments


【解决方案1】:

因为我自己是 Lua 的新手,所以我也有同样的问题。因为,在我看来,没有令人满意的答案,我想我会写一个,即使这个问题可能永远不会结束。希望这会对这种情况下的其他人有所帮助。

ma​​in.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 )

【讨论】:

  • 在我的测试中,您需要删除 lua_pushvalue( L, 1 ); 才能使此代码正常工作,否则您可能会收到 Failed to call the callback! 错误
  • 经过更多测试,我发现这个实现在异步程序中不起作用,因为当你调用回调时无法获得有效的lua_State。我也尝试保存lua_State,但获得了访问权限违规。
【解决方案2】:

在堆栈上有函数复制它后,使用lua_pushvalue

更新:每次要调用函数时都需要调用 lua_pushvalue(),因为使用 lua_pcall() 或 lua_call() 会从堆栈中弹出函数。

【讨论】:

  • 这有效,但仅适用于第一个循环。 :S 我想我找到了答案,我会更新第一篇文章。