# 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` 個上值。