第一版为 Lua 5.0 编写。虽然对于后续版本而言仍具有很大关联性,但也有一些差异。
第四版针对 Lua 5.3,可在 Amazon 和其他书店购买。
购买本书,您还可以帮助 支持 Lua 项目


25.2 – 调用 Lua 函数

Lua 的一大优势在于配置文件可以定义应用程序要调用的函数。例如,您可以编写一个应用程序来绘制函数的图形,并使用 Lua 来定义要绘制的函数。

调用函数的 API 协议很简单:首先,您推送要调用的函数;其次,您推送调用参数;然后,您使用 lua_pcall 执行实际调用;最后,您从堆栈中弹出结果。

作为一个示例,让我们假设我们的配置文件有一个类似于以下内容的函数

    function f (x, y)
      return (x^2 * math.sin(y))/(1 - x)
    end
并且您希望在 C 中计算 z = f(x, y),其中 xy 已知。假设您已经打开了 Lua 库并运行了配置文件,则可以将此调用封装在以下 C 函数中
    /* call a function `f' defined in Lua */
    double f (double x, double y) {
      double z;
    
      /* push functions and arguments */
      lua_getglobal(L, "f");  /* function to be called */
      lua_pushnumber(L, x);   /* push 1st argument */
      lua_pushnumber(L, y);   /* push 2nd argument */
    
      /* do the call (2 arguments, 1 result) */
      if (lua_pcall(L, 2, 1, 0) != 0)
        error(L, "error running function `f': %s",
                 lua_tostring(L, -1));
    
      /* retrieve result */
      if (!lua_isnumber(L, -1))
        error(L, "function `f' must return a number");
      z = lua_tonumber(L, -1);
      lua_pop(L, 1);  /* pop returned value */
      return z;
    }

您使用要传递的参数数量和想要的结果数量来调用 lua_pcall。第四个参数表示错误处理函数;我们稍后会讨论它。与 Lua 赋值一样,lua_pcall 会根据您的要求调整实际结果数量,根据需要推送 nil 或丢弃额外值。在推送结果之前,lua_pcall 会从堆栈中移除函数及其参数。如果函数返回多个结果,则首先推送第一个结果;因此,如果有 n 个结果,第一个结果将在索引 -n 处,最后一个结果将在索引 -1 处。

如果在运行 lua_pcall 时出现任何错误,lua_pcall 会返回一个非零值;此外,它还会将错误消息压入堆栈(但仍然会弹出函数及其参数)。然而,在压入消息之前,lua_pcall 会调用错误处理函数(如果有)。要指定错误处理函数,我们使用 lua_pcall 的最后一个参数。零表示没有错误处理函数;也就是说,最终错误消息就是原始消息。否则,该参数应该是错误处理函数在堆栈中的索引。请注意,在这种情况下,必须在要调用的函数及其参数之前将处理程序压入堆栈。

对于常规错误,lua_pcall 返回错误代码 LUA_ERRRUN。两种特殊类型的错误需要不同的代码,因为它们永远不会运行错误处理程序。第一种是内存分配错误。对于此类错误,lua_pcall 始终返回 LUA_ERRMEM。第二种是在 Lua 运行错误处理程序本身时发生的错误。在这种情况下,再次调用错误处理程序几乎没有用,因此 lua_pcall 会立即返回代码 LUA_ERRERR