# 4 – 编程接口
这个部分描述了 Lua 的 C API , 也就是宿主程序跟 Lua 通讯用的一组 C 函数。 所有的 API 函数按相关的类型以及常量都声明在头文件 `lua.h` 中。
虽然我们说的是“函数”, 但一部分简单的 API 是以宏的形式提供的。 除非另有说明, 所有的这些宏都只使用它们的参数一次 (除了第一个参数,那一定是 Lua 状态), 因此你不需担心这些宏的展开会引起一些副作用。
C 库中所有的 Lua API 函数都不去检查参数是否相容及有效。 然而,你可以在编译 Lua 时加上打开一个宏开关 `LUA_USE_APICHECK` 来改变这个行为。
## 4.1 – 栈
Lua 使用一个 _虚拟栈_ 来和 C 互传值。 栈上的的每个元素都是一个 Lua 值 (**nil**,数字,字符串,等等)。
无论何时 Lua 调用 C,被调用的函数都得到一个新的栈, 这个栈独立于 C 函数本身的栈,也独立于之前的 Lua 栈。 它里面包含了 Lua 传递给 C 函数的所有参数, 而 C 函数则把要返回的结果放入这个栈以返回给调用者 (参见 [`lua_CFunction`](#lua_CFunction))。
方便起见, 所有针对栈的 API 查询操作都不严格遵循栈的操作规则。 而是可以用一个 _索引_ 来指向栈上的任何元素: 正的索引指的是栈上的绝对位置(从1开始); 负的索引则指从栈顶开始的偏移量。 展开来说,如果堆栈有 _n_ 个元素, 那么索引 1 表示第一个元素 (也就是最先被压栈的元素) 而索引 _n_ 则指最后一个元素; 索引 -1 也是指最后一个元素 (即栈顶的元素), 索引 _-n_ 是指第一个元素。
## 4.2 – 栈大小
当你使用 Lua API 时, 就有责任保证做恰当的调用。 特别需要注意的是, _你有责任控制不要堆栈溢出_。 你可以使用 [`lua_checkstack`](#lua_checkstack) 这个函数来扩大可用堆栈的尺寸。
无论何时 Lua 调用 C , 它都只保证至少有 `LUA_MINSTACK` 这么多的堆栈空间可以使用。 `LUA_MINSTACK` 一般被定义为 20 , 因此,只要你不是不断的把数据压栈, 通常你不用关心堆栈大小。
当你调用一个 Lua 函数却没有指定要接收多少个返回值时 (参见 [`lua_call`](#lua_call)), Lua 可以保证栈一定有足够的空间来接收所有的返回值, 但不保证此外留有额外的空间。 因此,在做了一次这样的调用后,如果你需要继续压栈, 则需要使用 [`lua_checkstack`](#lua_checkstack)。
## 4.3 – 有效索引与可接受索引
API 中的函数若需要传入栈索引,这个索引必须是 _有效索引_ 或是 _可接受索引_。
_有效索引_ 指引用栈内真实位置的索引; 即在 1 到栈顶之间的位置 (`1 ≤ abs(index) ≤ top`)。 通常,一个可能修改该位置的值的函数需要传入有效索引。
除非另有说明, 任何可以接受有效索引的函数同时也接受 _伪索引_。 伪索引指代一些可以被 C code 访问得到 Lua 值,而它们又不在栈内。 这用于访问注册表以及 C 函数的上值(参见 [§4.4](#4.4))。
对于那些只是需要栈中的值(例如查询函数) 而不需要指定一个栈位置的函数, 可以用一个可接受的索引去调用它们。 _可接受索引_ 不仅可以是任何包括伪索引在内的有效索引, 还可以是任何超过栈顶但落在为栈分配出来的空间内的正索引。 (注意 0 永远都不是一个可接受索引。) 除非另有说明,API 里的函数都接受可接受索引。
允许可接受索引是为了避免对栈顶以外的查询时做额外的检查。 例如,C 函数可以直接查询传给它的第三个参数, 而不用先检查是不是有第三个参数, 即不需要检查 3 是不是一个有效索引。
对于那些以可接受索引调用的函数, 无效索引被看作包含了一个虚拟类型 `LUA_TNONE` 的值, 这个值的行为和 nil 一致。
## 4.4 – C 闭包
当 C 函数被创建出来, 我们有可能会把一些值关联在一起, 也就是创建一个 _C 闭包_ (参见 [`lua_pushcclosure`](#lua_pushcclosure)); 这些被关联起来的值被叫做 _上值_ , 它们可以在函数被调用的时候访问的到。
无论何时去调用 C 函数, 函数的上值都可以用伪索引定位。 我们可以用 [`lua_upvalueindex`](#lua_upvalueindex) 这个宏来生成这些伪索引。 第一个关联到函数的值放在 `lua_upvalueindex(1)` 位置处,依此类推。 使用 `lua_upvalueindex(_n_)` 时, 若 _n_ 大于当前函数的总上值个数 (但不可以大于 256)会产生一个可接受的但无效的索引。
## 4.5 – 注册表
Lua 提供了一个 _注册表_, 这是一个预定义出来的表, 可以用来保存任何 C 代码想保存的 Lua 值。 这个表可以用有效伪索引 `LUA_REGISTRYINDEX` 来定位。 任何 C 库都可以在这张表里保存数据, 为了防止冲突,你需要特别小心的选择键名。 一般的用法是,你可以用一个包含你的库名的字符串做为键名, 或者取你自己 C 对象的地址,以轻量用户数据的形式做键, 还可以用你的代码创建出来的任意 Lua 对象做键。 关于变量名,字符串键名中以下划线加大写字母的名字被 Lua 保留。
注册表中的整数键用于引用机制 (参见 [`luaL_ref`](#luaL_ref)), 以及一些预定义的值。 因此,整数键不要用于别的目的。
当你创建了一个新的 Lua 状态机, 其中的注册表内就预定义好了几个值。 这些预定义值可以用整数索引到, 这些整数以常数形式定义在 `lua.h` 中。 有下列常数:
* **`LUA_RIDX_MAINTHREAD`:** 注册表中这个索引下是状态机的主线程。 (主线程和状态机同时被创建出来。)
* **`LUA_RIDX_GLOBALS`:** 注册表的这个索引下是全局环境。
## 4.6 – C 中的错误处理
在内部实现中,Lua 使用了 C 的 `longjmp` 机制来处理错误。 (如果你使用 C++ 编译,Lua 将换成异常; 细节请在源代码中搜索 `LUAI_THROW`。) 当 Lua 碰到任何错误 (比如内存分配错误、类型错误、语法错误、还有运行时错误) 它都会 _抛出_一个错误出去; 也就是调用一次长跳转。 在 _保护环境_ 下, Lua 使用 `setjmp` 来设置一个恢复点; 任何发生的错误都会跳转到最近的一个恢复点。
如果错误发生在保护环境之外, Lua 会先调用 _panic 函数_ (参见 [`lua_atpanic`](#lua_atpanic)) 然后调用 `abort` 来退出宿主程序。 你的 panic 函数只要不返回 (例如:长跳转到你在 Lua 外你自己设置的恢复点) 就可以不退出程序。
panic 函数以错误消息处理器(参见 [§2.3](#2.3))的方式运行; 错误消息在栈顶。 不同的是,它不保证栈空间。 做任何压栈操作前,panic 函数都必须先检查是否有足够的空间 (参见 [§4.2](#4.2))。
大多数 API 函数都有可能抛出错误, 例如在内存分配错误时就会抛出。 每个函数的文档都会注明它是否可能抛出错误。
在 C 函数内部,你可以通过调用 [`lua_error`](#lua_error) 来抛出错误。
## 4.7 – C 中的让出处理
Lua 内部使用 C 的 `longjmp` 机制让出一个协程。 因此,如果一个 C 函数 `foo` 调用了一个 API 函数, 而这个 API 函数让出了(直接或间接调用了让出函数)。 由于 `longjmp` 会移除 C 栈的栈帧, Lua 就无法返回到 `foo` 里了。
为了回避这类问题, 碰到 API 调用中调用让出时,除了那些抛出错误的 API 外,还提供了三个函数: [`lua_yieldk`](#lua_yieldk), [`lua_callk`](#lua_callk),和 [`lua_pcallk`](#lua_pcallk) 。 它们在让出发生时,可以从传入的 _延续函数_ (名为 `k` 的参数)继续运行。
我们需要预设一些术语来解释延续点。 对于从 Lua 中调用的 C 函数,我们称之为 _原函数_。 从这个原函数中调用的上面所述的三个 C API 函数我们称之为 _被调函数_。 被调函数可以使当前线程让出。 (让出发生在被调函数是 [`lua_yieldk`](#lua_yieldk), 或传入 [`lua_callk`](#lua_callk) 或 [`lua_pcallk`](#lua_pcallk) 的函数调用了让出时。)
假设正在运行的线程在执行被调函数时让出。 当再次延续这条线程,它希望继续被调函数的运行。 然而,被调函数不可能返回到原函数中。 这是因为之前的让出操作破坏了 C 栈的栈帧。 作为替代品,Lua 调用那个作为被调函数参数给出的 _延续函数_ 。 正如其名,延续函数将延续原函数的任务。
下面的函数会做一个说明:
```
int original_function (lua_State *L) {
... /* code 1 */
status = lua_pcall(L, n, m, h); /* calls Lua */
... /* code 2 */
}
```
现在我们想允许被 [`lua_pcall`](#lua_pcall) 运行的 Lua 代码让出。 首先,我们把函数改写成这个样子:
```
int k (lua_State *L, int status, lua_KContext ctx) {
... /* code 2 */
}
int original_function (lua_State *L) {
... /* code 1 */
return k(L, lua_pcall(L, n, m, h), ctx);
}
```
上面的代码中,新函数 `k` 就是一个 _延续函数_ (函数类型为 [`lua_KFunction`](#lua_KFunction))。 它的工作就是原函数中调用 [`lua_pcall`](#lua_pcall) 之后做的那些事情。 现在我们必须通知 Lua 说,你必须在被 [`lua_pcall`](#lua_pcall) 执行的 Lua 代码发生过中断(错误或让出)后, 还得继续调用 `k` 。 所以我们还得继续改写这段代码,把 [`lua_pcall`](#lua_pcall) 替换成 [`lua_pcallk`](#lua_pcallk):
```
int original_function (lua_State *L) {
... /* code 1 */
return k(L, lua_pcallk(L, n, m, h, ctx2, k), ctx1);
}
```
注意这里那个额外的显式的对延续函数的调用: Lua 仅在需要时,这可能是由错误导致的也可能是发生了让出而需要继续运行,才会调用延续函数。 如果没有发生过任何让出,调用的函数正常返回, 那么 [`lua_pcallk`](#lua_pcallk) (以及 [`lua_callk`](#lua_callk))也会正常返回。 (当然,这个例子中你也可以不在之后调用延续函数, 而是在原函数的调用后直接写上需要做的工作。)
除了 Lua 状态,延续函数还有两个参数: 一个是调用最后的状态码,另一个一开始由 [`lua_pcallk`](#lua_pcallk) 传入的上下文 (`ctx`)。 (Lua 本身不使用这个值;它仅仅从原函数转发这个值给延续函数。) 对于 [`lua_pcallk`](#lua_pcallk) 而言, 状态码和 [`lua_pcallk`](#lua_pcallk) 本应返回值相同,区别仅在于发生过让出后才执行完时,状态码为 [`LUA_YIELD`](#pdf-LUA_YIELD)(而不是 [`LUA_OK`](#pdf-LUA_OK))。 对于 [`lua_yieldk`](#lua_yieldk) 和 [`lua_callk`](#lua_callk) 而言, 调用延续函数传入的状态码一定是 [`LUA_YIELD`](#pdf-LUA_YIELD)。 (对这两个函数,Lua 不会因任何错误而调用延续函数。 因为它们并不处理错误。) 同样,当你使用 [`lua_callk`](#lua_callk) 时, 你应该用 [`LUA_OK`](#pdf-LUA_OK) 作为状态码来调用延续函数。 (对于 [`lua_yieldk`](#lua_yieldk), 几乎没有什么地方需要直接调用延续函数, 因为 [`lua_yieldk`](#lua_yieldk) 本身并不会返回。)
Lua 会把延续函数看作原函数。 延续函数将接收到和原函数相同的 Lua 栈,其接收到的 lua 状态也和 被调函数若返回后应该有的状态一致。 (例如, [`lua_callk`](#lua_callk) 调用之后, 栈中之前压入的函数和调用参数都被调用产生的返回值所替代。) 这时也有相同的上值。 等到它返回的时候,Lua 会将其看待成原函数的返回去操作。
## 4.8 – 函数和类型
这里按字母次序列出了所有 C API 中的函数和类型。 每个函数都有一个这样的提示: [-o, +p, _x_]
对于第一个域,`o`, 指的是该函数会从栈上弹出多少个元素。 第二个域,`p`, 指该函数会将多少个元素压栈。 (所有函数都会在弹出参数后再把结果压栈。) `x|y` 这种形式的域表示该函数根据具体情况可能压入(或弹出) `x` 或 `y` 个元素; 问号 '`?`' 表示 我们无法仅通过参数来了解该函数会弹出/压入多少元素 (比如,数量取决于栈上有些什么)。 第三个域,`x`, 解释了该函数是否会抛出错误: '`-`' 表示该函数绝对不会抛出错误; '`e`' 表示该函数可能抛出错误; '`v`' 表示该函数可能抛出有意义的错误。
### `lua_absindex`
[-0, +0, –]
```
int lua_absindex (lua_State *L, int idx);
```
将一个可接受的索引 `idx` 转换为绝对索引 (即,一个不依赖栈顶在哪的值)。
### `lua_Alloc`
```
typedef void * (*lua_Alloc) (void *ud,
void *ptr,
size_t osize,
size_t nsize);
```
Lua 状态机中使用的内存分配器函数的类型。 内存分配函数必须提供一个功能类似于 `realloc` 但又不完全相同的函数。 它的参数有 `ud` ,一个由 [`lua_newstate`](#lua_newstate) 传给它的指针; `ptr` ,一个指向已分配出来/将被重新分配/要释放的内存块指针; `osize` ,内存块原来的尺寸或是关于什么将被分配出来的代码; `nsize` ,新内存块的尺寸。
如果 `ptr` 不是 `NULL`, `osize` 是 `ptr` 指向的内存块的尺寸, 即这个内存块当初被分配或重分配的尺寸。
如果 `ptr` 是 `NULL`, `osize` 是 Lua 即将分配对象类型的编码。 当(且仅当)Lua 创建一个对应类型的新对象时, `osize` 是 [`LUA_TSTRING`](#pdf-LUA_TSTRING),[`LUA_TTABLE`](#pdf-LUA_TTABLE),[`LUA_TFUNCTION`](#pdf-LUA_TFUNCTION), [`LUA_TUSERDATA`](#pdf-LUA_TUSERDATA),或 [`LUA_TTHREAD`](#pdf-LUA_TTHREAD) 中的一个。 若 `osize` 是其它类型,Lua 将为其它东西分配内存。
Lua 假定分配器函数会遵循以下行为:
当 `nsize` 是零时, 分配器必须和 `free` 行为类似并返回 `NULL`。
当 `nsize` 不是零时, 分配器必须和 `realloc` 行为类似。 如果分配器无法完成请求,返回 `NULL`。 Lua 假定在 `osize >= nsize` 成立的条件下, 分配器绝不会失败。
这里有一个简单的分配器函数的实现。 这个实现被放在补充库中,供 [`luaL_newstate`](#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);
}
```
注意,标准 C 能确保 `free(NULL)` 没有副作用, 且 `realloc(NULL,size)` 等价于 `malloc(size)`。 这段代码假定 `realloc` 在缩小块长度时不会失败。 (虽然标准 C 没有对此行为做出保证,但这看起来是一个安全的假定。)
### `lua_arith`
[-(2|1), +1, _e_]
```
void lua_arith (lua_State *L, int op);
```
对栈顶的两个值(或者一个,比如取反)做一次数学或位操作。 其中,栈顶的那个值是第二个操作数。 它会弹出压入的值,并把结果放在栈顶。 这个函数遵循 Lua 对应的操作符运算规则 (即有可能触发元方法)。
`op` 的值必须是下列常量中的一个:
* **`LUA_OPADD`:** 加法 (`+`)
* **`LUA_OPSUB`:** 减法 (`-`)
* **`LUA_OPMUL`:** 乘法 (`*`)
* **`LUA_OPDIV`:** 浮点除法 (`/`)
* **`LUA_OPIDIV`:** 向下取整的除法 (`//`)
* **`LUA_OPMOD`:** 取模 (`%`)
* **`LUA_OPPOW`:** 乘方 (`^`)
* **`LUA_OPUNM`:** 取负 (一元 `-`)
* **`LUA_OPBNOT`:** 按位取反 (`~`)
* **`LUA_OPBAND`:** 按位与 (`&`)
* **`LUA_OPBOR`:** 按位或 (`|`)
* **`LUA_OPBXOR`:** 按位异或 (`~`)
* **`LUA_OPSHL`:** 左移 (`<<`)
* **`LUA_OPSHR`:** 右移 (`>>`)
### `lua_atpanic`
[-0, +0, –]
```
lua_CFunction lua_atpanic (lua_State *L, lua_CFunction panicf);
```
设置一个新的 panic 函数,并返回之前设置的那个。 (参见 [§4.6](#4.6))。
### `lua_call`
[-(nargs+1), +nresults, _e_]
```
void lua_call (lua_State *L, int nargs, int nresults);
```
调用一个函数。
要调用一个函数请遵循以下协议: 首先,要调用的函数应该被压入栈; 接着,把需要传递给这个函数的参数按正序压栈; 这是指第一个参数首先压栈。 最后调用一下 [`lua_call`](#lua_call); `nargs` 是你压入栈的参数个数。 当函数调用完毕后,所有的参数以及函数本身都会出栈。 而函数的返回值这时则被压栈。 返回值的个数将被调整为 `nresults` 个, 除非 `nresults` 被设置成 `LUA_MULTRET`。 在这种情况下,所有的返回值都被压入堆栈中。 Lua 会保证返回值都放入栈空间中。 函数返回值将按正序压栈(第一个返回值首先压栈), 因此在调用结束后,最后一个返回值将被放在栈顶。
被调用函数内发生的错误将(通过 `longjmp` )一直上抛。
下面的例子中,这行 Lua 代码等价于在宿主程序中用 C 代码做一些工作:
```
a = f("how", t.x, 14)
```
这里是 C 里的代码:
```
lua_getglobal(L, "f"); /* function to be called */
lua_pushliteral(L, "how"); /* 1st argument */
lua_getglobal(L, "t"); /* table to be indexed */
lua_getfield(L, -1, "x"); /* push result of t.x (2nd arg) */
lua_remove(L, -2); /* remove 't' from the stack */
lua_pushinteger(L, 14); /* 3rd argument */
lua_call(L, 3, 1); /* call 'f' with 3 arguments and 1 result */
lua_setglobal(L, "a"); /* set global 'a' */
```
注意上面这段代码是 _平衡_ 的: 到了最后,堆栈恢复成原有的配置。 这是一种良好的编程习惯。
### `lua_callk`
[-(nargs + 1), +nresults, _e_]
```
void lua_callk (lua_State *L,
int nargs,
int nresults,
lua_KContext ctx,
lua_KFunction k);
```
这个函数的行为和 [`lua_call`](#lua_call) 完全一致,只不过它还允许被调用的函数让出 (参见 [§4.7](#4.7))。
### `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.0;
int i;
for (i = 1; i <= n; i++) {
if (!lua_isnumber(L, i)) {
lua_pushliteral(L, "incorrect argument");
lua_error(L);
}
sum += lua_tonumber(L, i);
}
lua_pushnumber(L, sum/n); /* 第一个返回值 */
lua_pushnumber(L, sum); /* 第二个返回值 */
return 2; /* 返回值的个数 */
}
```
### `lua_checkstack`
[-0, +0, –]
```
int lua_checkstack (lua_State *L, int n);
```
确保堆栈上至少有 `n` 个额外空位。 如果不能把堆栈扩展到相应的尺寸,函数返回假。 失败的原因包括将把栈扩展到比固定最大尺寸还大 (至少是几千个元素)或分配内存失败。 这个函数永远不会缩小堆栈; 如果堆栈已经比需要的大了,那么就保持原样。
### `lua_close`
[-0, +0, –]
```
void lua_close (lua_State *L);
```
销毁指定 Lua 状态机中的所有对象 (如果有垃圾收集相关的元方法的话,会调用它们), 并且释放状态机中使用的所有动态内存。 在一些平台上,你可以不必调用这个函数, 因为当宿主程序结束的时候,所有的资源就自然被释放掉了。 另一方面,长期运行的程序,比如一个后台程序或是一个网站服务器, 会创建出多个 Lua 状态机。那么就应该在不需要时赶紧关闭它们。
### `lua_compare`
[-0, +0, _e_]
```
int lua_compare (lua_State *L, int index1, int index2, int op);
```
比较两个 Lua 值。 当索引 `index1` 处的值通过 `op` 和索引 `index2` 处的值做比较后条件满足,函数返回 1 。 这个函数遵循 Lua 对应的操作规则(即有可能触发元方法)。 反之,函数返回 0。 当任何一个索引无效时,函数也会返回 0 。
`op` 值必须是下列常量中的一个:
* **`LUA_OPEQ`:** 相等比较 (`==`)
* **`LUA_OPLT`:** 小于比较 (`<`)
* **`LUA_OPLE`:** 小于等于比较 (`<=`)
### `lua_concat`
[-n, +1, _e_]
```
void lua_concat (lua_State *L, int n);
```
连接栈顶的 `n` 个值, 然后将这些值出栈,并把结果放在栈顶。 如果 `n` 为 1 ,结果就是那个值放在栈上(即,函数什么都不做); 如果 `n` 为 0 ,结果是一个空串。 连接依照 Lua 中通常语义完成(参见 [§3.4.6](#3.4.6) )。
### `lua_copy`
[-0, +0, –]
```
void lua_copy (lua_State *L, int fromidx, int toidx);
```
从索引 `fromidx` 处复制一个值到一个有效索引 `toidx` 处,覆盖那里的原有值。 不会影响其它位置的值。
### `lua_createtable`
[-0, +1, _e_]
```
void lua_createtable (lua_State *L, int narr, int nrec);
```
创建一张新的空表压栈。 参数 `narr` 建议了这张表作为序列使用时会有多少个元素; 参数 `nrec` 建议了这张表可能拥有多少序列之外的元素。 Lua 会使用这些建议来预分配这张新表。 如果你知道这张表用途的更多信息,预分配可以提高性能。 否则,你可以使用函数 [`lua_newtable`](#lua_newtable) 。
### `lua_dump`
[-0, +0, _e_]
```
int lua_dump (lua_State *L,
lua_Writer writer,
void *data,
int strip);
```
把函数导出成二进制代码块 。 函数接收栈顶的 Lua 函数做参数, 然后生成它的二进制代码块。 若被导出的东西被再次加载, 加载的结果就相当于原来的函数。 当它在产生代码块的时候, [`lua_dump`](#lua_dump) 通过调用函数 `writer` (参见 [`lua_Writer`](#lua_Writer) ) 来写入数据,后面的 `data` 参数会被传入 `writer` 。
如果 `strip` 为真, 二进制代码块将不包含该函数的调试信息。
最后一次由 `writer` 的返回值将作为这个函数的返回值返回; 0 表示没有错误。
该函数不会把 Lua 函数弹出堆栈。
### `lua_error`
[-1, +0, _v_]
```
int lua_error (lua_State *L);
```
以栈顶的值作为错误对象,抛出一个 Lua 错误。 这个函数将做一次长跳转,所以一定不会返回 (参见 [`luaL_error`](#luaL_error))。
### `lua_gc`
[-0, +0, _e_]
```
int lua_gc (lua_State *L, int what, int data);
```
控制垃圾收集器。
这个函数根据其参数 `what` 发起几种不同的任务:
* **`LUA_GCSTOP`:** 停止垃圾收集器。
* **`LUA_GCRESTART`:** 重启垃圾收集器。
* **`LUA_GCCOLLECT`:** 发起一次完整的垃圾收集循环。
* **`LUA_GCCOUNT`:** 返回 Lua 使用的内存总量(以 K 字节为单位)。
* **`LUA_GCCOUNTB`:** 返回当前内存使用量除以 1024 的余数。
* **`LUA_GCSTEP`:** 发起一步增量垃圾收集。
* **`LUA_GCSETPAUSE`:** 把 `data` 设为 _垃圾收集器间歇率_ (参见 [§2.5](#2.5)),并返回之前设置的值。
* **`LUA_GCSETSTEPMUL`:** 把 `data` 设为 _垃圾收集器步进倍率_ (参见 [§2.5](#2.5)),并返回之前设置的值。
* **`LUA_GCISRUNNING`:** 返回收集器是否在运行(即没有停止)。
关于这些选项的细节,参见 [`collectgarbage`](#pdf-collectgarbage) 。
### `lua_getallocf`
[-0, +0, –]
```
lua_Alloc lua_getallocf (lua_State *L, void **ud);
```
返回给定状态机的内存分配器函数。 如果 `ud` 不是 `NULL` , Lua 把设置内存分配函数时设置的那个指针置入 `*ud` 。
### `lua_getfield`
[-0, +1, _e_]
```
int lua_getfield (lua_State *L, int index, const char *k);
```
把 `t[k]` 的值压栈, 这里的 `t` 是索引指向的值。 在 Lua 中,这个函数可能触发对应 "index" 事件对应的元方法 (参见 [§2.4](#2.4) )。
函数将返回压入值的类型。
### `lua_getextraspace`
[-0, +0, –]
```
void *lua_getextraspace (lua_State *L);
```
返回一个 Lua 状态机中关联的内存块指针。 程序可以把这块内存用于任何用途;而 Lua 不会使用它。
每一个新线程都会携带一块内存, 初始化为主线程的这块内存的副本。
默认配置下,这块内存的大小为空指针的大小。 不过你可以重新编译 Lua 设定这块内存不同的大小。 (参见 `luaconf.h` 中的 `LUA_EXTRASPACE`。)
### `lua_getglobal`
[-0, +1, _e_]
```
int lua_getglobal (lua_State *L, const char *name);
```
把全局变量 <name>name</name> 里的值压栈,返回该值的类型。
### `lua_geti`
[-0, +1, _e_]
```
int lua_geti (lua_State *L, int index, lua_Integer i);
```
把 `t[i]` 的值压栈, 这里的 `t` 指给定的索引指代的值。 和在 Lua 里一样,这个函数可能会触发 "index" 事件的元方法 (参见 [§2.4](#2.4))。
返回压入值的类型。
### `lua_getmetatable`
[-0, +(0|1), –]
```
int lua_getmetatable (lua_State *L, int index);
```
如果该索引处的值有元表,则将其元表压栈,返回 1 。 否则不会将任何东西入栈,返回 0 。
### `lua_gettable`
[-1, +1, _e_]
```
int lua_gettable (lua_State *L, int index);
```
把 `t[k]` 的值压栈, 这里的 `t` 是指索引指向的值, 而 `k` 则是栈顶放的值。
这个函数会弹出堆栈上的键,把结果放在栈上相同位置。 和在 Lua 中一样, 这个函数可能触发对应 "index" 事件的元方法 (参见 [§2.4](#2.4) )。
返回压入值的类型。
### `lua_gettop`
[-0, +0, –]
```
int lua_gettop (lua_State *L);
```
返回栈顶元素的索引。 因为索引是从 1 开始编号的, 所以这个结果等于栈上的元素个数; 特别指出,0 表示栈为空。
### `lua_getuservalue`
[-0, +1, –]
```
int lua_getuservalue (lua_State *L, int index);
```
将给定索引处的用户数据所关联的 Lua 值压栈。
返回压入值的类型。
### `lua_insert`
[-1, +1, –]
```
void lua_insert (lua_State *L, int index);
```
把栈顶元素移动到指定的有效索引处, 依次移动这个索引之上的元素。 不要用伪索引来调用这个函数, 因为伪索引没有真正指向栈上的位置。
### `lua_Integer`
```
typedef ... lua_Integer;
```
Lua 中的整数类型。
缺省时,这个就是 `long long`, (通常是一个 64 位以二为补码的整数), 也可以修改它为 `long` 或 `int` (通常是一个 32 位以二为补码的整数)。 (参见 `luaconf.h` 中的 `LUA_INT` 。)
Lua 定义了两个常量: `LUA_MININTEGER` 和 `LUA_MAXINTEGER` 来表示这个类型可以表示的最小和最大值。
### `lua_isboolean`
[-0, +0, –]
```
int lua_isboolean (lua_State *L, int index);
```
当给定索引的值是一个布尔量时,返回 1 ,否则返回 0 。
### `lua_iscfunction`
[-0, +0, –]
```
int lua_iscfunction (lua_State *L, int index);
```
当给定索引的值是一个 C 函数时,返回 1 ,否则返回 0 。
### `lua_isfunction`
[-0, +0, –]
```
int lua_isfunction (lua_State *L, int index);
```
当给定索引的值是一个函数( C 或 Lua 函数均可)时,返回 1 ,否则返回 0 。
### `lua_isinteger`
[-0, +0, –]
```
int lua_isinteger (lua_State *L, int index);
```
当给定索引的值是一个整数 (其值是一个数字,且内部以整数储存), 时,返回 1 ,否则返回 0 。
### `lua_islightuserdata`
[-0, +0, –]
```
int lua_islightuserdata (lua_State *L, int index);
```
当给定索引的值是一个轻量用户数据时,返回 1 ,否则返回 0 。
### `lua_isnil`
[-0, +0, –]
```
int lua_isnil (lua_State *L, int index);
```
当给定索引的值是 **nil** 时,返回 1 ,否则返回 0 。
### `lua_isnone`
[-0, +0, –]
```
int lua_isnone (lua_State *L, int index);
```
当给定索引无效时,返回 1 ,否则返回 0 。
### `lua_isnoneornil`
[-0, +0, –]
```
int lua_isnoneornil (lua_State *L, int index);
```
当给定索引无效或其值是 **nil** 时, 返回 1 ,否则返回 0 。
### `lua_isnumber`
[-0, +0, –]
```
int lua_isnumber (lua_State *L, int index);
```
当给定索引的值是一个数字,或是一个可转换为数字的字符串时,返回 1 ,否则返回 0 。
### `lua_isstring`
[-0, +0, –]
```
int lua_isstring (lua_State *L, int index);
```
当给定索引的值是一个字符串或是一个数字 (数字总能转换成字符串)时,返回 1 ,否则返回 0 。
### `lua_istable`
[-0, +0, –]
```
int lua_istable (lua_State *L, int index);
```
当给定索引的值是一张表时,返回 1 ,否则返回 0 。
### `lua_isthread`
[-0, +0, –]
```
int lua_isthread (lua_State *L, int index);
```
当给定索引的值是一条线程时,返回 1 ,否则返回 0 。
### `lua_isuserdata`
[-0, +0, –]
```
int lua_isuserdata (lua_State *L, int index);
```
当给定索引的值是一个用户数据(无论是完全的还是轻量的)时, 返回 1 ,否则返回 0 。
### `lua_isyieldable`
[-0, +0, –]
```
int lua_isyieldable (lua_State *L);
```
如果给定的协程可以让出,返回 1 ,否则返回 0 。
### `lua_KContext`
```
typedef ... lua_KContext;
```
延续函数上下文参数的类型。 这一定是一个数字类型。 当有 `intptr_t` 时,被定义为 `intptr_t` , 因此它也可以保存指针。 否则,它被定义为 `ptrdiff_t`。
### `lua_KFunction`
```
typedef int (*lua_KFunction) (lua_State *L, int status, lua_KContext ctx);
```
延续函数的类型(参见 [§4.7](#4.7) )。
### `lua_len`
[-0, +1, _e_]
```
void lua_len (lua_State *L, int index);
```
返回给定索引的值的长度。 它等价于 Lua 中的 '`#`' 操作符 (参见 [§3.4.7](#3.4.7))。 它有可能触发 "length" 事件对应的元方法 (参见 [§2.4](#2.4) )。 结果压栈。
### `lua_load`
[-0, +1, –]
```
int lua_load (lua_State *L,
lua_Reader reader,
void *data,
const char *chunkname,
const char *mode);
```
加载一段 Lua 代码块,但不运行它。 如果没有错误, `lua_load` 把一个编译好的代码块作为一个 Lua 函数压到栈顶。 否则,压入错误消息。
`lua_load` 的返回值可以是:
* **[`LUA_OK`](#pdf-LUA_OK):** 没有错误;
* **`LUA_ERRSYNTAX`:** 在预编译时碰到语法错误;
* **[`LUA_ERRMEM`](#pdf-LUA_ERRMEM):** 内存分配错误;
* **[`LUA_ERRGCMM`](#pdf-LUA_ERRGCMM):** 在运行 `__gc` 元方法时出错了。 (这个错误和代码块加载过程无关,它是由垃圾收集器引发的。)
`lua_load` 函数使用一个用户提供的 `reader` 函数来读取代码块(参见 [`lua_Reader`](#lua_Reader) )。 `data` 参数会被传入 `reader` 函数。
`chunkname` 这个参数可以赋予代码块一个名字, 这个名字被用于出错信息和调试信息(参见 [§4.9](#4.9))。
`lua_load` 会自动检测代码块是文本的还是二进制的, 然后做对应的加载操作(参见程序 `luac` )。 字符串 `mode` 的作用和函数 [`load`](#pdf-load) 一致。 它还可以是 `NULL` 等价于字符串 "`bt`"。
`lua_load` 的内部会使用栈, 因此 reader 函数必须永远在每次返回时保留栈的原样。
如果返回的函数有上值, 第一个上值会被设置为 保存在注册表(参见 [§4.5](#4.5)) `LUA_RIDX_GLOBALS` 索引处的全局环境。 在加载主代码块时,这个上值是 `_ENV` 变量(参见 [§2.2](#2.2))。 其它上值均被初始化为 **nil**。
### `lua_newstate`
[-0, +0, –]
```
lua_State *lua_newstate (lua_Alloc f, void *ud);
```
创建一个运行在新的独立的状态机中的线程。 如果无法创建线程或状态机(由于内存有限)则返回 `NULL`。 参数 `f` 是一个分配器函数; Lua 将通过这个函数做状态机内所有的内存分配操作。 第二个参数 `ud` ,这个指针将在每次调用分配器时被转入。
### `lua_newtable`
[-0, +1, _e_]
```
void lua_newtable (lua_State *L);
```
创建一张空表,并将其压栈。 它等价于 `lua_createtable(L, 0, 0)` 。
### `lua_newthread`
[-0, +1, _e_]
```
lua_State *lua_newthread (lua_State *L);
```
创建一条新线程,并将其压栈, 并返回维护这个线程的 [`lua_State`](#lua_State) 指针。 这个函数返回的新线程共享原线程的全局环境, 但是它有独立的运行栈。
没有显式的函数可以用来关闭或销毁掉一个线程。 线程跟其它 Lua 对象一样是垃圾收集的条目之一。
### `lua_newuserdata`
[-0, +1, _e_]
```
void *lua_newuserdata (lua_State *L, size_t size);
```
这个函数分配一块指定大小的内存块, 把内存块地址作为一个完全用户数据压栈, 并返回这个地址。 宿主程序可以随意使用这块内存。
### `lua_next`
[-1, +(2|0), _e_]
```
int lua_next (lua_State *L, int index);
```
从栈顶弹出一个键, 然后把索引指定的表中的一个键值对压栈 (弹出的键之后的 “下一” 对)。 如果表中以无更多元素, 那么 [`lua_next`](#lua_next) 将返回 0 (什么也不压栈)。
典型的遍历方法是这样的:
```
/* 表放在索引 't' 处 */
lua_pushnil(L); /* 第一个键 */
while (lua_next(L, t) != 0) {
/* 使用 '键' (在索引 -2 处) 和 '值' (在索引 -1 处)*/
printf("%s - %s\n",
lua_typename(L, lua_type(L, -2)),
lua_typename(L, lua_type(L, -1)));
/* 移除 '值' ;保留 '键' 做下一次迭代 */
lua_pop(L, 1);
}
```
在遍历一张表的时候, 不要直接对键调用 [`lua_tolstring`](#lua_tolstring) , 除非你知道这个键一定是一个字符串。 调用 [`lua_tolstring`](#lua_tolstring) 有可能改变给定索引位置的值; 这会对下一次调用 [`lua_next`](#lua_next) 造成影响。
关于迭代过程中修改被迭代的表的注意事项参见 [`next`](#pdf-next) 函数。
### `lua_Number`
```
typedef double lua_Number;
```
Lua 中浮点数的类型。
Lua 中数字的类型。缺省是 double ,但是你可以改成 float 。 (参见 `luaconf.h` 中的 `LUA_REAL` 。)
### `lua_numbertointeger`
```
int lua_numbertointeger (lua_Number n, lua_Integer *p);
```
将一个 Lua 浮点数转换为一个 Lua 整数。 这个宏假设 `n` 有对应的整数值。 如果该值在 Lua 整数可表示范围内, 就将其转换为一个整数赋给 `*p`。 宏的结果是一个布尔量,表示转换是否成功。 (注意、由于圆整关系,这个范围测试不用此宏很难做对。)
该宏有可能对其参数做多次取值。
### `lua_pcall`
[-(nargs + 1), +(nresults|1), –]
```
int lua_pcall (lua_State *L, int nargs, int nresults, int msgh);
```
以保护模式调用一个函数。
`nargs` 和 `nresults` 的含义与 [`lua_call`](#lua_call) 中的相同。 如果在调用过程中没有发生错误, [`lua_pcall`](#lua_pcall) 的行为和 [`lua_call`](#lua_call) 完全一致。 但是,如果有错误发生的话, [`lua_pcall`](#lua_pcall) 会捕获它, 然后把唯一的值(错误消息)压栈,然后返回错误码。 同 [`lua_call`](#lua_call) 一样, [`lua_pcall`](#lua_pcall) 总是把函数本身和它的参数从栈上移除。
如果 `msgh` 是 0 , 返回在栈顶的错误消息就和原始错误消息完全一致。 否则, `msgh` 就被当成是 _错误处理函数_ 在栈上的索引位置。 (在当前的实现里,这个索引不能是伪索引。) 在发生运行时错误时, 这个函数会被调用而参数就是错误消息。 错误处理函数的返回值将被 [`lua_pcall`](#lua_pcall) 作为错误消息返回在堆栈上。
典型的用法中,错误处理函数被用来给错误消息加上更多的调试信息, 比如栈跟踪信息。 这些信息在 [`lua_pcall`](#lua_pcall) 返回后, 由于栈已经展开,所以收集不到了。
[`lua_pcall`](#lua_pcall) 函数会返回下列常数 (定义在 `lua.h` 内)中的一个:
* **`LUA_OK` (0):** 成功。
* **`LUA_ERRRUN`:** 运行时错误。
* **`LUA_ERRMEM`:** 内存分配错误。对于这种错,Lua 不会调用错误处理函数。
* **`LUA_ERRERR`:** 在运行错误处理函数时发生的错误。
* **`LUA_ERRGCMM`:** 在运行 `__gc` 元方法时发生的错误。 (这个错误和被调用的函数无关。)
### `lua_pcallk`
[-(nargs + 1), +(nresults|1), –]
```
int lua_pcallk (lua_State *L,
int nargs,
int nresults,
int msgh,
lua_KContext ctx,
lua_KFunction k);
```
这个函数的行为和 [`lua_pcall`](#lua_pcall) 完全一致,只不过它还允许被调用的函数让出 (参见 [§4.7](#4.7))。
### `lua_pop`
[-n, +0, –]
```
void lua_pop (lua_State *L, int n);
```
从栈中弹出 `n` 个元素。
### `lua_pushboolean`
[-0, +1, –]
```
void lua_pushboolean (lua_State *L, int b);
```
把 `b` 作为一个布尔量压栈。
### `lua_pushcclosure`
[-n, +1, _e_]
```
void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n);
```
把一个新的 C 闭包压栈。
当创建了一个 C 函数后, 你可以给它关联一些值, 这就是在创建一个 C 闭包(参见 [§4.4](#4.4)); 接下来无论函数何时被调用,这些值都可以被这个函数访问到。 为了将一些值关联到一个 C 函数上, 首先这些值需要先被压入堆栈(如果有多个值,第一个先压)。 接下来调用 [`lua_pushcclosure`](#lua_pushcclosure) 来创建出闭包并把这个 C 函数压到栈上。 参数 `n` 告之函数有多少个值需要关联到函数上。 [`lua_pushcclosure`](#lua_pushcclosure) 也会把这些值从栈上弹出。
`n` 的最大值是 255 。
当 `n` 为零时, 这个函数将创建出一个 _轻量 C 函数_, 它就是一个指向 C 函数的指针。 这种情况下,不可能抛出内存错误。
### `lua_pushcfunction`
[-0, +1, –]
```
void lua_pushcfunction (lua_State *L, lua_CFunction f);
```
将一个 C 函数压栈。 这个函数接收一个 C 函数指针, 并将一个类型为 `function` 的 Lua 值压栈。 当这个栈顶的值被调用时,将触发对应的 C 函数。
注册到 Lua 中的任何函数都必须遵循正确的协议来接收参数和返回值 (参见 [`lua_CFunction`](#lua_CFunction) )。
`lua_pushcfunction` 是作为一个宏定义出现的:
```
#define lua_pushcfunction(L,f) lua_pushcclosure(L,f,0)
```
### `lua_pushfstring`
[-0, +1, _e_]
```
const char *lua_pushfstring (lua_State *L, const char *fmt, ...);
```
把一个格式化过的字符串压栈, 然后返回这个字符串的指针。 它和 C 函数 `sprintf` 比较像, 不过有一些重要的区别:
* 你不需要为结果分配空间: 其结果是一个 Lua 字符串,由 Lua 来关心其内存分配 (同时通过垃圾收集来释放内存)。
* 这个转换非常的受限。 不支持符号、宽度、精度。 转换符只支持 '`%%`' (插入一个字符 '`%`'), '`%s`' (插入一个带零终止符的字符串,没有长度限制), '`%f`' (插入一个 [`lua_Number`](#lua_Number)), '`%L`' (插入一个 [`lua_Integer`](#lua_Integer)), '`%p`' (插入一个指针或是一个十六进制数), '`%d`' (插入一个 `int`), '`%c`' (插入一个用 `int` 表示的单字节字符),以及 '`%U`' (插入一个用 `long int` 表示的 UTF-8 字)。
### `lua_pushglobaltable`
[-0, +1, –]
```
void lua_pushglobaltable (lua_State *L);
```
将全局环境压栈。
### `lua_pushinteger`
[-0, +1, –]
```
void lua_pushinteger (lua_State *L, lua_Integer n);
```
把值为 `n` 的整数压栈。
### `lua_pushlightuserdata`
[-0, +1, –]
```
void lua_pushlightuserdata (lua_State *L, void *p);
```
把一个轻量用户数据压栈。
用户数据是保留在 Lua 中的 C 值。 _轻量用户数据_ 表示一个指针 `void*`。 它是一个像数字一样的值: 你不需要专门创建它,它也没有独立的元表,而且也不会被收集(因为从来不需要创建)。 只要表示的 C 地址相同,两个轻量用户数据就相等。
### `lua_pushliteral`
[-0, +1, _e_]
```
const char *lua_pushliteral (lua_State *L, const char *s);
```
这个宏等价于 [`lua_pushlstring`](#lua_pushlstring), 区别仅在于只能在 `s` 是一个字面量时才能用它。 它会自动给出字符串的长度。
### `lua_pushlstring`
[-0, +1, _e_]
```
const char *lua_pushlstring (lua_State *L, const char *s, size_t len);
```
把指针 `s` 指向的长度为 `len` 的字符串压栈。 Lua 对这个字符串做一个内部副本(或是复用一个副本), 因此 `s` 处的内存在函数返回后,可以释放掉或是立刻重用于其它用途。 字符串内可以是任意二进制数据,包括零字符。
返回内部副本的指针。
### `lua_pushnil`
[-0, +1, –]
```
void lua_pushnil (lua_State *L);
```
将空值压栈。
### `lua_pushnumber`
[-0, +1, –]
```
void lua_pushnumber (lua_State *L, lua_Number n);
```
把一个值为 `n` 的浮点数压栈。
### `lua_pushstring`
[-0, +1, _e_]
```
const char *lua_pushstring (lua_State *L, const char *s);
```
将指针 s 指向的零结尾的字符串压栈。 因此 `s` 处的内存在函数返回后,可以释放掉或是立刻重用于其它用途。
返回内部副本的指针。
如果 `s` 为 `NULL`,将 **nil** 压栈并返回 `NULL`。
### `lua_pushthread`
[-0, +1, –]
```
int lua_pushthread (lua_State *L);
```
把 `L` 表示的线程压栈。 如果这个线程是当前状态机的主线程的话,返回 1 。
### `lua_pushvalue`
[-0, +1, –]
```
void lua_pushvalue (lua_State *L, int index);
```
把栈上给定索引处的元素作一个副本压栈。
### `lua_pushvfstring`
[-0, +1, _e_]
```
const char *lua_pushvfstring (lua_State *L,
const char *fmt,
va_list argp);
```
等价于 [`lua_pushfstring`](#lua_pushfstring) , 不过是用 `va_list` 接收参数,而不是用可变数量的实际参数。
### `lua_rawequal`
[-0, +0, –]
```
int lua_rawequal (lua_State *L, int index1, int index2);
```
如果索引 `index1` 与索引 `index2` 处的值 本身相等(即不调用元方法),返回 1 。 否则返回 0 。 当任何一个索引无效时,也返回 0 。
### `lua_rawget`
[-1, +1, –]
```
int lua_rawget (lua_State *L, int index);
```
类似于 [`lua_gettable`](#lua_gettable) , 但是作一次直接访问(不触发元方法)。
### `lua_rawgeti`
[-0, +1, –]
```
int lua_rawgeti (lua_State *L, int index, lua_Integer n);
```
把 `t[n]` 的值压栈, 这里的 `t` 是指给定索引处的表。 这是一次直接访问;就是说,它不会触发元方法。
返回入栈值的类型。
### `lua_rawgetp`
[-0, +1, –]
```
int lua_rawgetp (lua_State *L, int index, const void *p);
```
把 `t[k]` 的值压栈, 这里的 `t` 是指给定索引处的表, `k` 是指针 `p` 对应的轻量用户数据。 这是一次直接访问;就是说,它不会触发元方法。
返回入栈值的类型。
### `lua_rawlen`
[-0, +0, –]
```
size_t lua_rawlen (lua_State *L, int index);
```
返回给定索引处值的固有“长度”: 对于字符串,它指字符串的长度; 对于表;它指不触发元方法的情况下取长度操作('`#`')应得到的值; 对于用户数据,它指为该用户数据分配的内存块的大小; 对于其它值,它为 0 。
### `lua_rawset`
[-2, +0, _e_]
```
void lua_rawset (lua_State *L, int index);
```
类似于 [`lua_settable`](#lua_settable) , 但是是做一次直接赋值(不触发元方法)。
### `lua_rawseti`
[-1, +0, _e_]
```
void lua_rawseti (lua_State *L, int index, lua_Integer i);
```
等价于 `t[i] = v` , 这里的 `t` 是指给定索引处的表, 而 `v` 是栈顶的值。
这个函数会将值弹出栈。 赋值是直接的;即不会触发元方法。
### `lua_rawsetp`
[-1, +0, _e_]
```
void lua_rawsetp (lua_State *L, int index, const void *p);
```
等价于 `t[k] = v` , 这里的 `t` 是指给定索引处的表, `k` 是指针 `p` 对应的轻量用户数据。 而 `v` 是栈顶的值。
这个函数会将值弹出栈。 赋值是直接的;即不会触发元方法。
### `lua_Reader`
```
typedef const char * (*lua_Reader) (lua_State *L,
void *data,
size_t *size);
```
[`lua_load`](#lua_load) 用到的读取器函数, 每次它需要一块新的代码块的时候, [`lua_load`](#lua_load) 就调用读取器, 每次都会传入一个参数 `data` 。 读取器需要返回含有新的代码块的一块内存的指针, 并把 `size` 设为这块内存的大小。 内存块必须在下一次函数被调用之前一直存在。 读取器可以通过返回 `NULL` 或设 `size` 为 0 来指示代码块结束。 读取器可能返回多个块,每个块可以有任意的大于零的尺寸。
### `lua_register`
[-0, +0, _e_]
```
void lua_register (lua_State *L, const char *name, lua_CFunction f);
```
把 C 函数 `f` 设到全局变量 `name` 中。 它通过一个宏定义:
```
#define lua_register(L,n,f) \
(lua_pushcfunction(L, f), lua_setglobal(L, n))
```
### `lua_remove`
[-1, +0, –]
```
void lua_remove (lua_State *L, int index);
```
从给定有效索引处移除一个元素, 把这个索引之上的所有元素移下来填补上这个空隙。 不能用伪索引来调用这个函数,因为伪索引并不指向真实的栈上的位置。
### `lua_replace`
[-1, +0, –]
```
void lua_replace (lua_State *L, int index);
```
把栈顶元素放置到给定位置而不移动其它元素 (因此覆盖了那个位置处的值),然后将栈顶元素弹出。
### `lua_resume`
[-?, +?, –]
```
int lua_resume (lua_State *L, lua_State *from, int nargs);
```
在给定线程中启动或延续一条协程 。
要启动一个协程的话, 你需要把主函数以及它需要的参数压入线程栈; 然后调用 [`lua_resume`](#lua_resume) , 把 `nargs` 设为参数的个数。 这次调用会在协程挂起时或是结束运行后返回。 当函数返回时,堆栈中会有传给 [`lua_yield`](#lua_yield) 的所有值, 或是主函数的所有返回值。 当协程让出, [`lua_resume`](#lua_resume) 返回 [`LUA_YIELD`](#pdf-LUA_YIELD) , 若协程结束运行且没有任何错误时,返回 0 。 如果有错则返回错误代码(参见 [`lua_pcall`](#lua_pcall) )。
在发生错误的情况下, 堆栈没有展开, 因此你可以使用调试 API 来处理它。 错误消息放在栈顶在。
要延续一个协程, 你需要清除上次 [`lua_yield`](#lua_yield) 遗留下的所有结果, 你把需要传给 `yield` 作结果的值压栈, 然后调用 [`lua_resume`](#lua_resume) 。
参数 `from` 表示协程从哪个协程中来延续 `L` 的。 如果不存在这样一个协程,这个参数可以是 `NULL` 。
### `lua_rotate`
[-0, +0, –]
```
void lua_rotate (lua_State *L, int idx, int n);
```
把从 `idx` 开始到栈顶的元素轮转 `n` 个位置。 对于 `n` 为正数时,轮转方向是向栈顶的; 当 `n` 为负数时,向栈底方向轮转 `-n` 个位置。 `n` 的绝对值不可以比参于轮转的切片长度大。
### `lua_setallocf`
[-0, +0, –]
```
void lua_setallocf (lua_State *L, lua_Alloc f, void *ud);
```
把指定状态机的分配器函数换成带上用户数据 `ud` 的 `f` 。
### `lua_setfield`
[-1, +0, _e_]
```
void lua_setfield (lua_State *L, int index, const char *k);
```
做一个等价于 `t[k] = v` 的操作, 这里 `t` 是给出的索引处的值, 而 `v` 是栈顶的那个值。
这个函数将把这个值弹出栈。 跟在 Lua 中一样,这个函数可能触发一个 "newindex" 事件的元方法 (参见 [§2.4](#2.4))。
### `lua_setglobal`
[-1, +0, _e_]
```
void lua_setglobal (lua_State *L, const char *name);
```
从堆栈上弹出一个值,并将其设为全局变量 `name` 的新值。
### `lua_seti`
[-1, +0, _e_]
```
void lua_seti (lua_State *L, int index, lua_Integer n);
```
做一个等价于 `t[n] = v` 的操作, 这里 `t` 是给出的索引处的值, 而 `v` 是栈顶的那个值。
这个函数将把这个值弹出栈。 跟在 Lua 中一样,这个函数可能触发一个 "newindex" 事件的元方法 (参见 [§2.4](#2.4))。
### `lua_setmetatable`
[-1, +0, –]
```
void lua_setmetatable (lua_State *L, int index);
```
把一张表弹出栈,并将其设为给定索引处的值的元表。
### `lua_settable`
[-2, +0, _e_]
```
void lua_settable (lua_State *L, int index);
```
做一个等价于 `t[k] = v` 的操作, 这里 `t` 是给出的索引处的值, `v` 是栈顶的那个值, `k` 是栈顶之下的值。
这个函数会将键和值都弹出栈。 跟在 Lua 中一样,这个函数可能触发一个 "newindex" 事件的元方法 (参见 [§2.4](#2.4))。
### `lua_settop`
[-?, +?, –]
```
void lua_settop (lua_State *L, int index);
```
参数允许传入任何索引以及 0 。 它将把堆栈的栈顶设为这个索引。 如果新的栈顶比原来的大, 超出部分的新元素将被填为 **nil** 。 如果 `index` 为 0 , 把栈上所有元素移除。
### `lua_setuservalue`
[-1, +0, –]
```
void lua_setuservalue (lua_State *L, int index);
```
从栈上弹出一个值并将其设为给定索引处用户数据的关联值。
### `lua_State`
```
typedef struct lua_State lua_State;
```
一个不透明的结构, 它指向一条线程并间接(通过该线程)引用了整个 Lua 解释器的状态。 Lua 库是完全可重入的: 它没有任何全局变量。 状态机所有的信息都可以通过这个结构访问到。
这个结构的指针必须作为第一个参数传递给每一个库函数。 [`lua_newstate`](#lua_newstate) 是一个例外, 这个函数会从头创建一个 Lua 状态机。
### `lua_status`
[-0, +0, –]
```
int lua_status (lua_State *L);
```
返回线程 `L` 的状态。
正常的线程状态是 0 ([`LUA_OK`](#pdf-LUA_OK))。 当线程用 [`lua_resume`](#lua_resume) 执行完毕并抛出了一个错误时, 状态值是错误码。 如果线程被挂起,状态为 `LUA_YIELD` 。
你只能在状态为 [`LUA_OK`](#pdf-LUA_OK) 的线程中调用函数。 你可以延续一个状态为 [`LUA_OK`](#pdf-LUA_OK) 的线程 (用于开始新协程)或是状态为 [`LUA_YIELD`](#pdf-LUA_YIELD) 的线程 (用于延续协程)。
### `lua_stringtonumber`
[-0, +1, –]
```
size_t lua_stringtonumber (lua_State *L, const char *s);
```
将一个零结尾的字符串 `s` 转换为一个数字, 将这个数字压栈,并返回字符串的总长度(即长度加一)。 转换的结果可能是整数也可能是浮点数, 这取决于 Lua 的转换语法(参见 [§3.1](#3.1))。 这个字符串可以有前置和后置的空格以及符号。 如果字符串并非一个有效的数字,返回 0 并不把任何东西压栈。 (注意,这个结果可以当成一个布尔量使用,为真即转换成功。)
### `lua_toboolean`
[-0, +0, –]
```
int lua_toboolean (lua_State *L, int index);
```
把给定索引处的 Lua 值转换为一个 C 中的布尔量( 0 或是 1 )。 和 Lua 中做的所有测试一样, [`lua_toboolean`](#lua_toboolean) 会把任何不同于 **false** 和 **nil** 的值当作真返回; 否则就返回假。 (如果你想只接收真正的 boolean 值, 就需要使用 [`lua_isboolean`](#lua_isboolean) 来测试值的类型。)
### `lua_tocfunction`
[-0, +0, –]
```
lua_CFunction lua_tocfunction (lua_State *L, int index);
```
把给定索引处的 Lua 值转换为一个 C 函数。 这个值必须是一个 C 函数; 如果不是就返回 `NULL` 。
### `lua_tointeger`
[-0, +0, –]
```
lua_Integer lua_tointeger (lua_State *L, int index);
```
等价于调用 [`lua_tointegerx`](#lua_tointegerx), 其参数 `isnum` 为 `NULL`。
### `lua_tointegerx`
[-0, +0, –]
```
lua_Integer lua_tointegerx (lua_State *L, int index, int *isnum);
```
将给定索引处的 Lua 值转换为带符号的整数类型 [`lua_Integer`](#lua_Integer)。 这个 Lua 值必须是一个整数,或是一个可以被转换为整数 (参见 [§3.4.3](#3.4.3))的数字或字符串; 否则,`lua_tointegerx` 返回 0 。
如果 `isnum` 不是 `NULL`, `*isnum` 会被设为操作是否成功。
### `lua_tolstring`
[-0, +0, _e_]
```
const char *lua_tolstring (lua_State *L, int index, size_t *len);
```
把给定索引处的 Lua 值转换为一个 C 字符串。 如果 `len` 不为 `NULL` , 它还把字符串长度设到 `*len` 中。 这个 Lua 值必须是一个字符串或是一个数字; 否则返回返回 `NULL` 。 如果值是一个数字, `lua_tolstring` 还会 _把堆栈中的那个值的实际类型转换为一个字符串_。 (当遍历一张表的时候, 若把 `lua_tolstring` 作用在键上, 这个转换有可能导致 [`lua_next`](#lua_next) 弄错。)
`lua_tolstring` 返回一个已对齐指针 指向 Lua 状态机中的字符串。 这个字符串总能保证 ( C 要求的)最后一个字符为零 ('\0') , 而且它允许在字符串内包含多个这样的零。
因为 Lua 中可能发生垃圾收集, 所以不保证 `lua_tolstring` 返回的指针, 在对应的值从堆栈中移除后依然有效。
### `lua_tonumber`
[-0, +0, –]
```
lua_Number lua_tonumber (lua_State *L, int index);
```
等价于调用 [`lua_tonumberx`](#lua_tonumberx), 其参数 `isnum` 为 `NULL`。
### `lua_tonumberx`
[-0, +0, –]
```
lua_Number lua_tonumberx (lua_State *L, int index, int *isnum);
```
把给定索引处的 Lua 值转换为 [`lua_Number`](#lua_Number) 这样一个 C 类型 (参见 lua_Number )。 这个 Lua 值必须是一个数字或是一个可转换为数字的字符串 (参见 [§3.4.3](#3.4.3)); 否则, [`lua_tonumberx`](#lua_tonumberx) 返回 0 。
如果 `isnum` 不是 `NULL`, `*isnum` 会被设为操作是否成功。
### `lua_topointer`
[-0, +0, –]
```
const void *lua_topointer (lua_State *L, int index);
```
把给定索引处的值转换为一般的 C 指针 (`void*`) 。 这个值可以是一个用户对象,表 ,线程或是一个函数; 否则, `lua_topointer` 返回 `NULL` 。 不同的对象有不同的指针。 不存在把指针再转回原有类型的方法。
这个函数通常只用于调试信息。
### `lua_tostring`
[-0, +0, _e_]
```
const char *lua_tostring (lua_State *L, int index);
```
等价于调用 [`lua_tolstring`](#lua_tolstring) , 其参数 `len` 为 `NULL` 。
### `lua_tothread`
[-0, +0, –]
```
lua_State *lua_tothread (lua_State *L, int index);
```
把给定索引处的值转换为一个 Lua 线程 (表示为 `lua_State*`)。 这个值必须是一个线程; 否则函数返回 `NULL`。
### `lua_touserdata`
[-0, +0, –]
```
void *lua_touserdata (lua_State *L, int index);
```
如果给定索引处的值是一个完全用户数据, 函数返回其内存块的地址。 如果值是一个轻量用户数据, 那么就返回它表示的指针。 否则,返回 `NULL` 。
### `lua_type`
[-0, +0, –]
```
int lua_type (lua_State *L, int index);
```
返回给定有效索引处值的类型, 当索引无效(或无法访问)时则返回 `LUA_TNONE`。 [`lua_type`](#lua_type) 返回的类型被编码为一些个在 `lua.h` 中定义的常量: `LUA_TNIL`, `LUA_TNUMBER`, `LUA_TBOOLEAN`, `LUA_TSTRING`, `LUA_TTABLE`, `LUA_TFUNCTION`, `LUA_TUSERDATA`, `LUA_TTHREAD`, `LUA_TLIGHTUSERDATA`。
### `lua_typename`
[-0, +0, –]
```
const char *lua_typename (lua_State *L, int tp);
```
返回 `tp` 表示的类型名, 这个 `tp` 必须是 [`lua_type`](#lua_type) 可能返回的值中之一。
### `lua_Unsigned`
```
typedef ... lua_Unsigned;
```
[`lua_Integer`](#lua_Integer) 的无符号版本。
### `lua_upvalueindex`
[-0, +0, –]
```
int lua_upvalueindex (int i);
```
返回当前运行的函数(参见 [§4.4](#4.4))的第 `i` 个上值的伪索引。
### `lua_version`
[-0, +0, _v_]
```
const lua_Number *lua_version (lua_State *L);
```
返回保存在 Lua 内核中储存的版本数字的地址。 当调用时传入一个合法的 [`lua_State`](#lua_State) , 返回创建该状态机时的版本地址。 如果用 `NULL` 调用, 返回调用者的版本地址。
### `lua_Writer`
```
typedef int (*lua_Writer) (lua_State *L,
const void* p,
size_t sz,
void* ud);
```
被 [`lua_dump`](#lua_dump) 用到的写入器函数。 每次 [`lua_dump`](#lua_dump) 产生了一段新的代码块, 它都会调用写入器。 传入要写入的缓冲区 (`p`) 和它的尺寸 (`sz`) , 以及传给 [`lua_dump`](#lua_dump) 的参数 `data` 。
写入器会返回一个错误码: 0 表示没有错误; 别的值均表示一个错误, 并且会让 [`lua_dump`](#lua_dump) 停止再次调用写入器。
### `lua_xmove`
[-?, +?, –]
```
void lua_xmove (lua_State *from, lua_State *to, int n);
```
交换同一个状态机下不同线程中的值。
这个函数会从 `from` 的栈上弹出 `n` 个值, 然后把它们压入 `to` 的栈上。
### `lua_yield`
[-?, +?, _e_]
```
int lua_yield (lua_State *L, int nresults);
```
这个函数等价于调用 [`lua_yieldk`](#lua_yieldk), 不同的是不提供延续函数(参见 [§4.7](#4.7))。 因此,当线程被延续,线程会继续运行调用 `lua_yield` 函数的函数。
### `lua_yieldk`
[-?, +?, _e_]
```
int lua_yieldk (lua_State *L,
int nresults,
lua_KContext ctx,
lua_KFunction k);
```
让出协程(线程)。
当 C 函数调用了 [`lua_yieldk`](#lua_yieldk), 当前运行的协程会挂起, 启动这个线程的 [`lua_resume`](#lua_resume) 调用返回。 参数 `nresults` 指栈上需返回给 [`lua_resume`](#lua_resume) 的返回值的个数。
当协程再次被延续时, Lua 调用延续函数 `k` 继续运行被挂起(参见 [§4.7](#4.7))的 C 函数。 延续函数会从前一个函数中接收到相同的栈, 栈中的 `n` 个返回值被移除而压入了从 [`lua_resume`](#lua_resume) 传入的参数。 此外,延续函数还会收到传给 [`lua_yieldk`](#lua_yieldk) 的参数 `ctx`。
通常,这个函数不会返回; 当协程一次次延续,将从延续函数继续运行。 然而,有一个例外: 当这个函数从一个逐行运行的钩子函数(参见 [§4.9](#4.9)) 中调用时,`lua_yieldk` 不可以提供延续函数。 (也就是类似 [`lua_yield`](#lua_yield) 的形式), 而此时,钩子函数在调用完让出后将立刻返回。 Lua 会使协程让出,一旦协程再次被延续, 触发钩子的函数会继续正常运行。
当一个线程处于未提供延续函数的 C 调用中,调用它会抛出一个错误。 从并非用延续方式(例如:主线程)启动的线程中调用它也会这样。
## 4.9 – 调试接口
Lua 没有内置的调试机制。 但是它提供了一组特殊的函数接口以及 _钩子_。 这组接口可用于构建出不同的调试器、性能剖析器、 或是其它需要从解释器获取“内部信息”的工具。
### `lua_Debug`
```
typedef struct lua_Debug {
int event;
const char *name; /* (n) */
const char *namewhat; /* (n) */
const char *what; /* (S) */
const char *source; /* (S) */
int currentline; /* (l) */
int linedefined; /* (S) */
int lastlinedefined; /* (S) */
unsigned char nups; /* (u) 上值的数量 */
unsigned char nparams; /* (u) 参数的数量 */
char isvararg; /* (u) */
char istailcall; /* (t) */
char short_src[LUA_IDSIZE]; /* (S) */
/* 私有部分 */
_其它域_
} lua_Debug;
```
这是一个携带有有关函数或活动记录的各种信息的结构。 [`lua_getstack`](#lua_getstack) 只会填充结构的私有部分供后面使用。 调用 [`lua_getinfo`](#lua_getinfo) 可以在 [`lua_Debug`](#lua_Debug) 中填充那些可被使用的信息域。
下面对 [`lua_Debug`](#lua_Debug) 的各个域做一个说明:
* **`source`:** 创建这个函数的代码块的名字。 如果 `source` 以 '`@`' 打头, 指这个函数定义在一个文件中,而 '`@`' 之后的部分就是文件名。 若 `source` 以 '`=`' 打头, 剩余的部分由用户行为来决定如何表示源码。 其它的情况下,这个函数定义在一个字符串中, 而 `source` 正是那个字符串。
* **`short_src`:** 一个“可打印版本”的 `source` ,用于出错信息。
* **`linedefined`:** 函数定义开始处的行号。
* **`lastlinedefined`:** 函数定义结束处的行号。
* **`what`:** 如果函数是一个 Lua 函数,则为一个字符串 `"Lua"` ; 如果是一个 C 函数,则为 `"C"`; 如果它是一个代码块的主体部分,则为 `"main"`。
* **`currentline`:** 给定函数正在执行的那一行。 当提供不了行号信息的时候, `currentline` 被设为 -1 。
* **`name`:** 给定函数的一个合理的名字。 因为 Lua 中的函数是一等公民, 所以它们没有固定的名字: 一些函数可能是全局复合变量的值, 另一些可能仅仅只是被保存在一张表的某个域中。 `lua_getinfo` 函数会检查函数是怎样被调用的, 以此来找到一个适合的名字。 如果它找不到名字, `name` 就被设置为 `NULL` 。
* **`namewhat`:** 用于解释 `name` 域。 `namewhat` 的值可以是 `"global"`, `"local"`, `"method"`, `"field"`, `"upvalue"`, 或是 `""` (空串)。 这取决于函数怎样被调用。 (Lua 用空串表示其它选项都不符合。)
* **`istailcall`:** 如果函数以尾调用形式调用,这个值就为真。 在这种情况下,当层的调用者不在栈中。
* **`nups`:** 函数的上值个数。
* **`nparams`:** 函数固定形参个数 (对于 C 函数永远是 0 )。
* **`isvararg`:** 如果函数是一个可变参数函数则为真 (对于 C 函数永远为真)。
### `lua_gethook`
[-0, +0, –]
```
lua_Hook lua_gethook (lua_State *L);
```
返回当前的钩子函数。
### `lua_gethookcount`
[-0, +0, –]
```
int lua_gethookcount (lua_State *L);
```
返回当前的钩子计数。
### `lua_gethookmask`
[-0, +0, –]
```
int lua_gethookmask (lua_State *L);
```
返回当前的钩子掩码。
### `lua_getinfo`
[-(0|1), +(0|1|2), _e_]
```
int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar);
```
返回一个指定的函数或函数调用的信息。
当用于取得一次函数调用的信息时, 参数 `ar` 必须是一个有效的活动的记录。 这条记录可以是前一次调用 [`lua_getstack`](#lua_getstack) 得到的, 或是一个钩子 (参见 [`lua_Hook`](#lua_Hook) )得到的参数。
用于获取一个函数的信息时, 可以把这个函数压入堆栈, 然后把 `what` 字符串以字符 '`>`' 起头。 (这会让 `lua_getinfo` 从栈顶上弹出函数。) 例如,想知道函数 `f` 是在哪一行定义的, 你可以使用下列代码:
```
lua_Debug ar;
lua_getglobal(L, "f"); /* 取得全局变量 'f' */
lua_getinfo(L, ">S", &ar);
printf("%d\n", ar.linedefined);
```
`what` 字符串中的每个字符都筛选出结构 `ar` 结构中一些域用于填充, 或是把一个值压入堆栈:
* **'`n`':** 填充 `name` 及 `namewhat` 域;
* **'`S`':** 填充 `source` , `short_src` , `linedefined` , `lastlinedefined` ,以及 `what` 域;
* **'`l`':** 填充 `currentline` 域;
* **'`t`':** 填充 `istailcall` 域;
* **'`u`':** 填充 `nups`, `nparams`,及 `isvararg` 域;
* **'`f`':** 把正在运行中指定层次处函数压栈;
* **'`L`':** 将一张表压栈,这张表中的整数索引用于描述函数中哪些行是有效行。 (_有效行_指有实际代码的行,即你可以置入断点的行。 无效行包括空行和只有注释的行。)
如果这个选项和选项 '`f`' 同时使用, 这张表在函数之后压栈。
这个函数出错会返回 0 (例如,`what` 中有一个无效选项)。
### `lua_getlocal`
[-0, +(0|1), –]
```
const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n);
```
从给定活动记录或从一个函数中获取一个局部变量的信息。
对于第一种情况, 参数 `ar` 必须是一个有效的活动的记录。 这条记录可以是前一次调用 [`lua_getstack`](#lua_getstack) 得到的, 或是一个钩子 (参见 [`lua_Hook`](#lua_Hook) )的参数。 索引 `n` 用于选择要检阅哪个局部变量; 参见 [`debug.getlocal`](#pdf-debug.getlocal) 中关于变量的索引和名字的介绍。
[`lua_getlocal`](#lua_getlocal) 将变量的值压栈,并返回其名字。
对于第二种情况,`ar` 必须填 `NULL` 。 需要探知的函数必须放在栈顶。 对于这种情况,只有 Lua 函数的形参是可见的 (没有关于还有哪些活动变量的信息) 也不会有任何值压栈。
当索引大于活动的局部变量的数量, 返回 `NULL` (无任何压栈)
### `lua_getstack`
[-0, +0, –]
```
int lua_getstack (lua_State *L, int level, lua_Debug *ar);
```
获取解释器的运行时栈的信息。
这个函数用正在运行中的指定层次处函数的 _活动记录_ 来填写 [`lua_Debug`](#lua_Debug) 结构的一部分。 0 层表示当前运行的函数, _n+1_ 层的函数就是调用第 _n_ 层 (尾调用例外,它不算在栈层次中) 函数的那一个。 如果没有错误, [`lua_getstack`](#lua_getstack) 返回 1 ; 当调用传入的层次大于堆栈深度的时候,返回 0 。
### `lua_getupvalue`
[-0, +(0|1), –]
```
const char *lua_getupvalue (lua_State *L, int funcindex, int n);
```
获取一个闭包的上值信息。 (对于 Lua 函数,上值是函数需要使用的外部局部变量, 因此这些变量被包含在闭包中。) [`lua_getupvalue`](#lua_getupvalue) 获取第 `n` 个上值, 把这个上值的值压栈, 并且返回它的名字。 `funcindex` 指向闭包在栈上的位置。 ( 因为上值在整个函数中都有效,所以它们没有特别的次序。 因此,它们以字母次序来编号。)
当索引号比上值数量大的时候, 返回 `NULL`(而且不会压入任何东西)。 对于 C 函数,所有上值的名字都是空串 `""`。
### `lua_Hook`
```
typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar);
```
用于调试的钩子函数类型。
无论何时钩子被调用,它的参数 `ar` 中的 `event` 域都被设为触发钩子的事件。 Lua 把这些事件定义为以下常量: `LUA_HOOKCALL`,`LUA_HOOKRET`, `LUA_HOOKTAILCALL`,`LUA_HOOKLINE`, `LUA_HOOKCOUNT`。 除此之外,对于 line 事件, `currentline` 域也被设置。 要想获得 `ar` 中的其他域, 钩子必须调用 [`lua_getinfo`](#lua_getinfo) 。
对于 call 事件,`event` 可以是 `LUA_HOOKCALL` 这个通常值, 或是 `LUA_HOOKTAILCALL` 表示尾调用; 后一种情况,没有对应的返回事件。
当 Lua 运行在一个钩子内部时, 它将屏蔽掉其它对钩子的调用。 也就是说,如果一个钩子函数内再调回 Lua 来执行一个函数或是一个代码块 , 这个执行操作不会触发任何的钩子。
钩子函数不能有延续点, 即不能用一个非空的 `k` 调用 [`lua_yieldk`](#lua_yieldk), [`lua_pcallk`](#lua_pcallk),或 [`lua_callk`](#lua_callk)。
钩子函数可以在满足下列条件时让出: 只有行计数事件可以让出,且不能在让出时传出任何值; 从钩子里让出必须用 [`lua_yield`](#lua_yield) 来结束钩子的运行,且 `nresults` 必须为零。
### `lua_sethook`
[-0, +0, –]
```
void lua_sethook (lua_State *L, lua_Hook f, int mask, int count);
```
设置一个调试用钩子函数。
参数 `f` 是钩子函数。 `mask` 指定在哪些事件时会调用: 它由下列一组位常量构成 `LUA_MASKCALL`, `LUA_MASKRET`, `LUA_MASKLINE`, `LUA_MASKCOUNT`。 参数 `count` 只在掩码中包含有 `LUA_MASKCOUNT` 才有意义。 对于每个事件,钩子被调用的情况解释如下:
* **call hook:** 在解释器调用一个函数时被调用。 钩子将于 Lua 进入一个新函数后, 函数获取参数前被调用。
* **return hook:** 在解释器从一个函数中返回时调用。 钩子将于 Lua 离开函数之前的那一刻被调用。 没有标准方法来访问被函数返回的那些值。
* **line hook:** 在解释器准备开始执行新的一行代码时, 或是跳转到这行代码中时(即使在同一行内跳转)被调用。 (这个事件仅仅在 Lua 执行一个 Lua 函数时发生。)
* **count hook:** 在解释器每执行 `count` 条指令后被调用。 (这个事件仅仅在 Lua 执行一个 Lua 函数时发生。)
钩子可以通过设置 `mask` 为零屏蔽。
### `lua_setlocal`
[-(0|1), +0, –]
```
const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n);
```
设置给定活动记录中的局部变量的值。 参数 `ar` 与 `n` 和 [`lua_getlocal`](#lua_getlocal) 中的一样 (参见 [`lua_getlocal`](#lua_getlocal) )。 [`lua_setlocal`](#lua_setlocal) 把栈顶的值赋给变量然后返回变量的名字。 它会将值从栈顶弹出。
当索引大于活动局部变量的数量时,返回 `NULL` (什么也不弹出)。
### `lua_setupvalue`
[-(0|1), +0, –]
```
const char *lua_setupvalue (lua_State *L, int funcindex, int n);
```
设置闭包上值的值。 它把栈顶的值弹出并赋于上值并返回上值的名字。 参数 `funcindex` 与 `n` 和 [`lua_getupvalue`](#lua_getupvalue) 中的一样 (参见 [`lua_getupvalue`](#lua_getupvalue) )。
当索引大于上值的数量时,返回 `NULL` (什么也不弹出)。
### `lua_upvalueid`
[-0, +0, –]
```
void *lua_upvalueid (lua_State *L, int funcindex, int n);
```
返回索引 `funcindex` 处的闭包中 编号为 `n` 的上值的一个唯一标识符。 参数 `funcindex` 与 `n` 和 [`lua_getupvalue`](#lua_getupvalue) 中的一样 (参见 [`lua_getupvalue`](#lua_getupvalue) )。 (但 `n` 不可以大于上值的数量)。
这些唯一标识符可用于检测不同的闭包是否共享了相同的上值。 共享同一个上值的 Lua 闭包(即它们指的同一个外部局部变量) 会针对这个上值返回相同的标识。
### `lua_upvaluejoin`
[-0, +0, –]
```
void lua_upvaluejoin (lua_State *L, int funcindex1, int n1,
int funcindex2, int n2);
```
让索引 `funcindex1` 处的 Lua 闭包的第 `n1` 个上值 引用索引 `funcindex2` 处的 Lua 闭包的第 `n2` 个上值。