Lua 5.1 参考手册(六)

云风几年前译的Lua 5.1文档,这里直接转载过来,方便记录。原地址

3.7 - 函数和类型

在这里我们按字母次序列出了所有 C API 中的函数和类型。


lua_Alloc

typedef void * (*lua_Alloc) (void *ud,
                             void *ptr,
                             size_t osize,
                             size_t nsize);

Lua 状态机中使用的内存分配器函数的类型。 内存分配函数必须提供一个功能类似于 realloc 但又不完全相同的函数。 它的参数有 ud ,一个由 lua_newstate 传给它的指针; ptr ,一个指向已分配出来或是将被重新分配或是要释放的内存块指针; osize ,内存块原来的尺寸; nsize ,新内存块的尺寸。 如果且只有 osize 是零时,ptr 为 NULL 。 当 nsize 是零,分配器必须返回 NULL; 如果 osize 不是零,分配器应当释放掉 ptr 指向的内存块。 当 nsize 不是零,若分配器不能满足请求时,分配器返回 NULL 。 当 nsize 不是零而 osize 是零时,分配器应该和 malloc 有相同的行为。 当 nsize 和 osize 都不是零时,分配器则应和 realloc 保持一样的行为。 Lua 假设分配器在 osize >= nsize 时永远不会失败。

这里有一个简单的分配器函数的实现。 这个实现被放在补充库中,由 luaL_newstate 提供。

static void *l_alloc (void *ud, void *ptr, size_t osize,
                                           size_t nsize) {
  (void)ud;  (void)osize;  /* not used */
  if (nsize == 0) {
    free(ptr);
    return NULL;
  }
  else
    return realloc(ptr, nsize);
}

这段代码假设 free(NULL) 啥也不影响,而且 realloc(NULL, size) 等价于 malloc(size)。 这两点是 ANSI C 保证的行为。


lua_atpanic

lua_CFunction lua_atpanic (lua_State *L, lua_CFunction panicf);

设置一个新的 panic (恐慌) 函数,并返回前一个。

如果在保护环境之外发生了任何错误, Lua 就会调用一个 panic 函数,接着调用 exit(EXIT_FAILURE), 这样就开始退出宿主程序。 你的 panic 函数可以永远不返回(例如作一次长跳转)来避免程序退出。

panic 函数可以从栈顶取到出错信息。


lua_call

void lua_call (lua_State *L, int nargs, int nresults);

调用一个函数。

要调用一个函数请遵循以下协议: 首先,要调用的函数应该被压入堆栈; 接着,把需要传递给这个函数的参数按正序压栈; 这是指第一个参数首先压栈。 最后调用一下 lua_call; nargs 是你压入堆栈的参数个数。 当函数调用完毕后,所有的参数以及函数本身都会出栈。 而函数的返回值这时则被压入堆栈。 返回值的个数将被调整为 nresults 个, 除非 nresults 被设置成 LUA_MULTRET。 在这种情况下,所有的返回值都被压入堆栈中。 Lua 会保证返回值都放入栈空间中。 函数返回值将按正序压栈(第一个返回值首先压栈), 因此在调用结束后,最后一个返回值将被放在栈顶。

被调用函数内发生的错误将(通过 longjmp)一直上抛。

下面的例子中,这行 Lua 代码等价于在宿主程序用 C 代码做一些工作:

a = f("how", t.x, 14)

这里是 C 里的代码:

lua_getfield(L, LUA_GLOBALSINDEX, "f");          /* 将调用的函数 */
lua_pushstring(L, "how");                          /* 第一个参数 */
lua_getfield(L, LUA_GLOBALSINDEX, "t");          /* table 的索引 */
lua_getfield(L, -1, "x");         /* 压入 t.x 的值(第 2 个参数)*/
lua_remove(L, -2);                           /* 从堆栈中移去 't' */
lua_pushinteger(L, 14);                           /* 第 3 个参数 */
lua_call(L, 3, 1); /* 调用 'f',传入 3 个参数,并索取 1 个返回值 */
lua_setfield(L, LUA_GLOBALSINDEX, "a");      /* 设置全局变量 'a' */

注意上面这段代码是“平衡”的: 到了最后,堆栈恢复成原由的配置。 这是一种良好的编程习惯。


lua_CFunction

typedef int (*lua_CFunction) (lua_State *L);

C 函数的类型。

为了正确的和 Lua 通讯,C 函数必须使用下列 定义了参数以及返回值传递方法的协议: C 函数通过 Lua 中的堆栈来接受参数,参数以正序入栈(第一个参数首先入栈)。 因此,当函数开始的时候, lua_gettop(L) 可以返回函数收到的参数个数。 第一个参数(如果有的话)在索引 1 的地方,而最后一个参数在索引 lua_gettop(L) 处。 当需要向 Lua 返回值的时候,C 函数只需要把它们以正序压到堆栈上(第一个返回值最先压入), 然后返回这些返回值的个数。 在这些返回值之下的,堆栈上的东西都会被 Lua 丢掉。 和 Lua 函数一样,从 Lua 中调用 C 函数也可以有很多返回值。

下面这个例子中的函数将接收若干数字参数,并返回它们的平均数与和:

static int foo (lua_State *L) {
  int n = lua_gettop(L);    /* 参数的个数 */
  lua_Number sum = 0;
  int i;
  for (i = 1; i <= n; i++) {
    if (!lua_isnumber(L, i)) {
      lua_pushstring(L, "incorrect argument");
      lua_error(L);
    }
    sum += lua_tonumber(L, i);
  }
  lua_pushnumber(L, sum/n);   /* 第一个返回值 */
  lua_pushnumber(L, sum);     /* 第二个返回值 */
  return 2;                   /* 返回值的个数 */
}

lua_checkstack

int lua_checkstack (lua_State *L, int extra);

确保堆栈上至少有 extra 个空位。 如果不能把堆栈扩展到相应的尺寸,函数返回 false 。 这个函数永远不会缩小堆栈; 如果堆栈已经比需要的大了,那么就放在那里不会产生变化。


lua_close

void lua_close (lua_State *L);

销毁指定 Lua 状态机中的所有对象(如果有垃圾收集相关的元方法的话,会调用它们), 并且释放状态机中使用的所有动态内存。 在一些平台上,你可以不必调用这个函数, 因为当宿主程序结束的时候,所有的资源就自然被释放掉了。 另一方面,长期运行的程序,比如一个后台程序或是一个 web 服务器, 当不再需要它们的时候就应该释放掉相关状态机。这样可以避免状态机扩张的过大。


lua_concat

void lua_concat (lua_State *L, int n);

连接栈顶的 n 个值, 然后将这些值出栈,并把结果放在栈顶。 如果 n 为 1 ,结果就是一个字符串放在栈上(即,函数什么都不做); 如果 n 为 0 ,结果是一个空串。 连接依照 Lua 中创建语义完成(参见 §2.5.4 )。


lua_cpcall

int lua_cpcall (lua_State *L, lua_CFunction func, void *ud);

以保护模式调用 C 函数 func 。 func 只有能从堆栈上拿到一个参数,就是包含有 ud 的 light userdata。 当有错误时, lua_cpcall 返回和 lua_pcall 相同的错误代码, 并在栈顶留下错误对象; 否则它返回零,并不会修改堆栈。 所有从 func 内返回的值都会被扔掉。


lua_createtable

void lua_createtable (lua_State *L, int narr, int nrec);

创建一个新的空 table 压入堆栈。 这个新 table 将被预分配 narr 个元素的数组空间 以及 nrec 个元素的非数组空间。 当你明确知道表中需要多少个元素时,预分配就非常有用。 如果你不知道,可以使用函数 lua_newtable。


lua_dump

int lua_dump (lua_State *L, lua_Writer writer, void *data);

把函数 dump 成二进制 chunk 。 函数接收栈顶的 Lua 函数做参数,然后生成它的二进制 chunk 。 若被 dump 出来的东西被再次加载,加载的结果就相当于原来的函数。 当它在产生 chunk 的时候,lua_dump 通过调用函数 writer (参见 lua_Writer) 来写入数据,后面的 data 参数会被传入 writer 。

最后一次由写入器 (writer) 返回值将作为这个函数的返回值返回; 0 表示没有错误。

这个函数不会把 Lua 返回弹出堆栈。


lua_equal

int lua_equal (lua_State *L, int index1, int index2);

如果依照 Lua 中 == 操作符语义,索引 index1 和 index2 中的值相同的话,返回 1 。 否则返回 0 。 如果任何一个索引无效也会返回 0。


lua_error

int lua_error (lua_State *L);

产生一个 Lua 错误。 错误信息(实际上可以是任何类型的 Lua 值)必须被置入栈顶。 这个函数会做一次长跳转,因此它不会再返回。 (参见 luaL_error)。


lua_gc

int lua_gc (lua_State *L, int what, int data);

控制垃圾收集器。

这个函数根据其参数 what 发起几种不同的任务:


lua_getallocf

lua_Alloc lua_getallocf (lua_State *L, void **ud);

返回给定状态机的内存分配器函数。 如果 ud 不是 NULL ,Lua 把调用 lua_newstate 时传入的那个指针放入 *ud 。


lua_getfenv

void lua_getfenv (lua_State *L, int index);

把索引处值的环境表压入堆栈。