C++呼叫Lua API介面
3
這個部分描述了 Lua 的 C API ,也就是宿主程式跟 Lua 通訊用的一組 C 函式。所有的 API 函式按相關的型別以及常量都宣告在標頭檔案lua.h
中。
雖然我們說的是“函式”,但一部分簡單的 API 是以巨集的形式提供的。所有的這些巨集都只使用它們的引數一次(除了第一個引數,也就是 lua 狀態機),因此你不需擔心這些巨集的展開會引起一些副作用。
在所有的 C 庫中,Lua API 函式都不去檢查引數的有效性和堅固性。然而,你可以在編譯 Lua 時加上開啟一個巨集開關來開啟luaconf.h
檔案中的巨集 luai_apicheck
以改變這個行為。
3.1 - 堆疊
Lua 使用一個虛擬棧來和 C 傳遞值。棧上的的每個元素都是一個 Lua 值(nil,數字,字串,等等)。
無論何時 Lua 呼叫 C,被呼叫的函式都得到一個新的棧,這個棧獨立於 C 函式本身的堆疊,也獨立於以前的棧。(譯註:在 C 函式裡,用 Lua API 不能訪問到 Lua 狀態機中本次呼叫之外的堆疊中的資料)它裡面包含了 Lua 傳遞給 C 函式的所有引數,而 C 函式則把要返回的結果也放入堆疊以返回給呼叫者(參見lua_CFunction
)。
方便起見,所有針對棧的 API 查詢操作都不嚴格遵循棧的操作規則。而是可以用一個索引來指向棧上的任何元素:正的索引指的是棧上的絕對位置(從一開始);負的索引則指從棧頂開始的偏移量。更詳細的說明一下,如果堆疊有 n 個元素,那麼索引 1 表示第一個元素(也就是最先被壓入堆疊的元素)而索引 n 則指最後一個元素;索引 -1 也是指最後一個元素(即棧頂的元素),索引 -n 是指第一個元素。如果索引在 1 到棧頂之間(也就是,1 ≤ abs(index)
≤ top
)我們就說這是個有效的索引。
3.2 - 堆疊尺寸
當你使用 Lua API 時,就有責任保證其堅固性。特別需要注意的是,你有責任控制不要堆疊溢位。你可以使用lua_checkstack
這個函式來擴大可用堆疊的尺寸。
無論何時 Lua 呼叫 C ,它都只保證 LUA_MINSTACK
這麼多的堆疊空間可以使用。LUA_MINSTACK
一般被定義為
20 ,因此,只要你不是不斷的把資料壓棧,通常你不用關心堆疊大小。
所有的查詢函式都可以接收一個索引,只要這個索引是任何棧提供的空間中的值。棧能提供的最大空間是通過lua_checkstack
來設定的。這些索引被稱作可接受的索引,通常我們把它定義為:
(index < 0 && abs(index) <= top) ||
(index > 0 && index <= stackspace)
注意,0 永遠都不是一個可接受的索引。(譯註:下文中凡提到的索引,沒有特別註明的話,都指可接受的索引。)
3.3 - 偽索引
除了特別宣告外,任何一個函式都可以接受另一種有效的索引,它們被稱作“偽索引”。這個可以幫助 C 程式碼訪問一些並不在棧上的 Lua 值。偽索引被用來訪問執行緒的環境,函式的環境,登錄檔,還有 C 函式的 upvalue (參見§3.4)。
執行緒的環境(也就是全域性變數放的地方)通常在偽索引 LUA_GLOBALSINDEX
處。正在執行的 C 函式的環境則放在偽索引LUA_ENVIRONINDEX
之處。
你可以用常規的 table 操作來訪問和改變全域性變數的值,只需要指定環境表的位置。舉例而言,要訪問全域性變數的值,這樣做:
lua_getfield(L, LUA_GLOBALSINDEX, varname);
3.4 - C Closure
當 C 函式被建立出來,我們有可能會把一些值關聯在一起,也就是建立一個 C closure ;這些被關聯起來的值被叫做 upvalue ,它們可以在函式被呼叫的時候訪問的到。(參見lua_pushcclosure
)。
無論何時去呼叫 C 函式,函式的 upvalue 都被放在指定的偽索引處。我們可以用lua_upvalueindex
這個巨集來生成這些偽索引。第一個關聯到函式的值放在lua_upvalueindex(1)
位置處,依次類推。任何情況下都可以用lua_upvalueindex(
n)
產生一個
upvalue 的索引,即使 n 大於實際的 upvalue 數量也可以。它都可以產生一個可接受但不一定有效的索引。
3.5 - 登錄檔
Lua 提供了一個登錄檔,這是一個預定義出來的表,可以用來儲存任何 C 程式碼想儲存的 Lua 值。這個表可以用偽索引LUA_REGISTRYINDEX
來定位。任何
C 庫都可以在這張表裡儲存資料,為了防止衝突,你需要特別小心的選擇鍵名。一般的用法是,你可以用一個包含你的庫名的字串做為鍵名,或者可以取你自己 C 程式碼中的一個地址,以 light userdata 的形式做鍵。
登錄檔裡的整數健被用於補充庫中實現的引用系統的工作,一般說來不要把它們用於別的用途。
3.6 - C中的錯誤處理
在內部實現中,Lua 使用了 C 的 longjmp
機制來處理錯誤。(如果你使用 C++ 的話,也可以選擇換用異常;參見luaconf.h
檔案。)當 Lua 碰到任何錯誤(比如記憶體分配錯誤、型別錯誤、語法錯誤、還有一些執行時錯誤)它都會產生一個錯誤出去;也就是呼叫一個 long jump 。在保護環境下,Lua 使用setjmp
來設定一個恢復點;任何發生的錯誤都會啟用最近的一個恢復點。
幾乎所有的 API 函式都可能產生錯誤,例如記憶體分配錯誤。但下面的一些函式執行在保護環境中(也就是說它們建立了一個保護環境再在其中執行),因此它們不會產生錯誤出來:lua_newstate
,lua_close
,lua_load
,lua_pcall
,
andlua_cpcall
。
在 C 函式裡,你也可以通過呼叫 lua_error
產生一個錯誤。
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_GCSTOP
: 停止垃圾收集器。LUA_GCRESTART
: 重啟垃圾收集器。LUA_GCCOLLECT
: 發起一次完整的垃圾收集迴圈。LUA_GCCOUNT
: 返回 Lua 使用的記憶體總量(以 K 位元組為單位)。LUA_GCCOUNTB
: 返回當前記憶體使用量除以 1024 的餘數。LUA_GCSTEP
: 發起一步增量垃圾收集。步數由data
控制(越大的值意味著越多步),而其具體含義(具體數字表示了多少)並未標準化。如果你想控制這個步數,必須實驗性的測試data
的值。如果這一步結束了一個垃圾收集週期,返回返回 1 。LUA_GCSETPAUSE
: 把data
/100 設定為 garbage-collector pause 的新值(參見§2.10)。函式返回以前的值。LUA_GCSETSTEPMUL
: 把arg
/100 設定成 step multiplier (參見§2.10)。函式返回以前的值。
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);
把索引處值的環境表壓入堆疊。
lua_getfield
void lua_getfield (lua_State *L, int index, const char *k);
把 t[k]
值壓入堆疊,這裡的 t
是指有效索引 index
指向的值。在 Lua 中,這個函式可能觸發對應 "index" 事件的元方法(參見 §2.8)。
lua_getglobal
void lua_getglobal (lua_State *L, const char *name);
把全域性變數 name
裡的值壓入堆疊。這個是用一個巨集定義出來的:
#define lua_getglobal(L,s) lua_getfield(L, LUA_GLOBALSINDEX, s)
lua_getmetatable
int lua_getmetatable (lua_State *L, int index);
把給定索引指向的值的元表壓入堆疊。如果索引無效,或是這個值沒有元表,函式將返回 0 並且不會向棧上壓任何東西。
lua_gettable
void lua_gettable (lua_State *L, int index);
把 t[k]
值壓入堆疊,這裡的 t
是指有效索引 index
指向的值,而 k
則是棧頂放的值。
這個函式會彈出堆疊上的 key (把結果放在棧上相同位置)。在 Lua 中,這個函式可能觸發對應 "index" 事件的元方法(參見§2.8)。
lua_gettop
int lua_gettop (lua_State *L);
返回棧頂元素的索引。因為索引是從 1 開始編號的,所以這個結果等於堆疊上的元素個數(因此返回 0 表示堆疊為空)。
lua_insert
void lua_insert (lua_State *L, int index);
把棧頂元素插入指定的有效索引處,並依次移動這個索引之上的元素。不要用偽索引來呼叫這個函式,因為偽索引不是真正指向堆疊上的位置。
lua_Integer
typedef ptrdiff_t lua_Integer;
這個型別被用於 Lua API 接收整數值。
預設時這個被定義為 ptrdiff_t
,這個東西通常是機器能處理的最大整數型別。
lua_isboolean
int lua_isboolean (lua_State *L, int index);
當給定索引的值型別為 boolean 時,返回 1 ,否則返回 0 。
lua_iscfunction
int lua_iscfunction (lua_State *L, int index);
當給定索引的值是一個 C 函式時,返回 1 ,否則返回 0 。
lua_isfunction
int lua_isfunction (lua_State *L, int index);
當給定索引的值是一個函式( C 或 Lua 函式均可)時,返回 1 ,否則返回 0 。
lua_islightuserdata
int lua_islightuserdata (lua_State *L, int index);
當給定索引的值是一個 light userdata 時,返回 1 ,否則返回 0 。
lua_isnil
int lua_isnil (lua_State *L, int index);
當給定索引的值是 nil 時,返回 1 ,否則返回 0 。
lua_isnumber
int lua_isnumber (lua_State *L, int index);
當給定索引的值是一個數字,或是一個可轉換為數字的字串時,返回 1 ,否則返回 0 。
lua_isstring
int lua_isstring (lua_State *L, int index);
當給定索引的值是一個字串或是一個數字(數字總能轉換成字串)時,返回 1 ,否則返回 0 。
lua_istable
int lua_istable (lua_State *L, int index);
當給定索引的值是一個 table 時,返回 1 ,否則返回 0 。
lua_isthread
int lua_isthread (lua_State *L, int index);
當給定索引的值是一個 thread 時,返回 1 ,否則返回 0 。
lua_isuserdata
int lua_isuserdata (lua_State *L, int index);
當給定索引的值是一個 userdata (無論是完整的 userdata 還是 light userdata )時,返回 1 ,否則返回 0 。
lua_lessthan
int lua_lessthan (lua_State *L, int index1, int index2);
如果索引 index1
處的值小於索引 index2
處的值時,返回 1 ;否則返回 0 。其語義遵循 Lua 中的 <
操作符(就是說,有可能呼叫元方法)。如果任何一個索引無效,也會返回 0 。
lua_load
int lua_load (lua_State *L,
lua_Reader reader,
void *data,
const char *chunkname);
載入一個 Lua chunk 。如果沒有錯誤, lua_load
把一個編譯好的
chunk 作為一個 Lua 函式壓入堆疊。否則,壓入出錯資訊。lua_load
的返回值可以是:
- 0: 沒有錯誤;
LUA_ERRSYNTAX
: 在預編譯時碰到語法錯誤;LUA_ERRMEM
: 記憶體分配錯誤。
這個函式僅僅加栽 chunk ;而不會去執行它。
lua_load
會自動檢測
chunk 是文字的還是二進位制的,然後做對應的載入操作(參見程式luac
)。
lua_load
函式使用一個使用者提供的reader
函式來讀取
chunk (參見 lua_Reader
)。 data
引數會被傳入讀取器函式。
chunkname
這個引數可以賦予 chunk 一個名字,這個名字被用於出錯資訊和除錯資訊(參見§3.8)。
lua_newstate
lua_State *lua_newstate (lua_Alloc f, void *ud);
建立的一個新的獨立的狀態機。如果建立不了(因為記憶體問題)返回 NULL
。引數 f
是一個分配器函式; Lua 將通過這個函式做狀態機內所有的記憶體分配操作。第二個引數 ud
,這個指標將在每次呼叫分配器時被直接傳入。
lua_newtable
void lua_newtable (lua_State *L);
建立一個空 table ,並將之壓入堆疊。它等價於 lua_createtable(L, 0, 0)
。
lua_newthread
lua_State *lua_newthread (lua_State *L);
建立一個新執行緒,並將其壓入堆疊,並返回維護這個執行緒的 lua_State
指標。這個函式返回的新狀態機共享原有狀態機中的所有物件(比如一些
table),但是它有獨立的執行堆疊。
沒有顯式的函式可以用來關閉或銷燬掉一個執行緒。執行緒跟其它 Lua 物件一樣是垃圾收集的條目之一。
lua_newuserdata
void *lua_newuserdata (lua_State *L, size_t size);
這個函式分配分配一塊指定大小的記憶體塊,把記憶體塊地址作為一個完整的 userdata 壓入堆疊,並返回這個地址。
userdata 代表 Lua 中的 C 值。完整的 userdata 代表一塊記憶體。它是一個物件(就像 table 那樣的物件):你必須建立它,它有著自己的元表,而且它在被回收時,可以被監測到。一個完整的 userdata 只和它自己相等(在等於的原生作用下)。
當 Lua 通過 gc
元方法回收一個完整的 userdata 時, Lua 呼叫這個元方法並把 userdata 標記為已終止。等到這個 userdata 再次被收集的時候,Lua 會釋放掉相關的記憶體。
lua_next
int lua_next (lua_State *L, int index);
從棧上彈出一個 key(鍵),然後把索引指定的表中 key-value(健值)對壓入堆疊(指定 key 後面的下一 (next) 對)。如果表中以無更多元素,那麼lua_next
將返回
0 (什麼也不壓入堆疊)。
典型的遍歷方法是這樣的:
/* table 放在索引 't' 處 */
lua_pushnil(L); /* 第一個 key */
while (lua_next(L, t) != 0) {
/* 用一下 'key' (在索引 -2 處) 和 'value' (在索引 -1 處) */
printf("%s - %s\n",
lua_typename(L, lua_type(L, -2)),
lua_typename(L, lua_type(L, -1)));
/* 移除 'value' ;保留 'key' 做下一次迭代 */
lua_pop(L, 1);
}
在遍歷一張表的時候,不要直接對 key 呼叫 lua_tolstring
,除非你知道這個
key 一定是一個字串。呼叫lua_tolstring
有可能改變給定索引位置的值;這會對下一次呼叫lua_next
造成影響。
lua_Number
typedef double lua_Number;
Lua 中數字的型別。確省是 double ,但是你可以在 luaconf.h
中修改它。
通過修改配置檔案你可以改變 Lua 讓它操作其它數字型別(例如:float 或是 long )。
lua_objlen
size_t lua_objlen (lua_State *L, int index);
返回指定的索引處的值的長度。對於 string ,那就是字串的長度;對於 table ,是取長度操作符 ('#
') 的結果;對於 userdata ,就是為其分配的記憶體塊的尺寸;對於其它值,為 0 。
lua_pcall
lua_pcall (lua_State *L, int nargs, int nresults, int errfunc);
以保護模式呼叫一個函式。
nargs
和 nresults
的含義與lua_call
中的相同。如果在呼叫過程中沒有發生錯誤,lua_pcall
的行為和lua_call
完全一致。但是,如果有錯誤發生的話,lua_pcall
會捕獲它,然後把單一的值(錯誤資訊)壓入堆疊,然後返回錯誤碼。同lua_call
一樣,lua_pcall
總是把函式本身和它的引數從棧上移除。
如果 errfunc
是 0 ,返回在棧頂的錯誤資訊就和原始錯誤資訊完全一致。否則,errfunc
就被當成是錯誤處理函式在棧上的索引。(在當前的實現裡,這個索引不能是偽索引。)在發生執行時錯誤時,這個函式會被呼叫而引數就是錯誤資訊。錯誤處理函式的返回值將被lua_pcall
作為出錯資訊返回在堆疊上。
典型的用法中,錯誤處理函式被用來在出錯資訊上加上更多的除錯資訊,比如棧跟蹤資訊 (stack traceback) 。這些資訊在lua_pcall
返回後,因為棧已經展開
(unwound) ,所以收集不到了。
lua_pcall
函式在呼叫成功時返回
0 ,否則返回以下(定義在lua.h
中的)錯誤程式碼中的一個:
LUA_ERRRUN
: 執行時錯誤。LUA_ERRMEM
: 記憶體分配錯誤。對於這種錯,Lua 呼叫不了錯誤處理函式。LUA_ERRERR
: 在執行錯誤處理函式時發生的錯誤。
lua_pop
void lua_pop (lua_State *L, int n);
從堆疊中彈出 n
個元素。
lua_pushboolean
void lua_pushboolean (lua_State *L, int b);
把 b
作為一個 boolean 值壓入堆疊。
lua_pushcclosure
void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n);
把一個新的 C closure 壓入堆疊。
當建立了一個 C 函式後,你可以給它關聯一些值,這樣就是在建立一個 C closure (參見§3.4);接下來無論函式何時被呼叫,這些值都可以被這個函式訪問到。為了將一些值關聯到一個
C 函式上,首先這些值需要先被壓入堆疊(如果有多個值,第一個先壓)。接下來呼叫lua_pushcclosure
來建立出
closure 並把這個 C 函式壓到堆疊上。引數n
告之函式有多少個值需要關聯到函式上。 lua_pushcclosure
也會把這些值從棧上彈出。
lua_pushcfunction
void lua_pushcfunction (lua_State *L, lua_CFunction f);
將一個 C 函式壓入堆疊。這個函式接收一個 C 函式指標,並將一個型別為function
的 Lua 值壓入堆疊。當這個棧頂的值被呼叫時,將觸發對應的 C 函式。
註冊到 Lua 中的任何函式都必須遵循正確的協議來接收引數和返回值(參見lua_CFunction
)。
lua_pushcfunction
是作為一個巨集定義出現的:
#define lua_pushcfunction(L,f) lua_pushcclosure(L,f,0)
lua_pushfstring
const char *lua_pushfstring (lua_State *L, const char *fmt, ...);
把一個格式化過的字串壓入堆疊,然後返回這個字串的指標。它和 C 函式sprintf
比較像,不過有一些重要的區別:
- 摸你需要為結果分配空間:其結果是一個 Lua 字串,由 Lua 來關心其記憶體分配(同時通過垃圾收集來釋放記憶體)。
- 這個轉換非常的受限。不支援 flag ,寬度,或是指定精度。它只支援下面這些: '
%%
' (插入一個 '%
'), '%s
' (插入一個帶零終止符的字串,沒有長度限制), '%f
' (插入一個lua_Number
), '%p
' (插入一個指標或是一個十六進位制數), '%d
' (插入一個int
), '%c
' (把一個int
作為一個字元插入)。
lua_pushinteger
void lua_pushinteger (lua_State *L, lua_Integer n);
把 n
作為一個數字壓棧。
lua_pushlightuserdata
void lua_pushlightuserdata (lua_State *L, void *p);
把一個 light userdata 壓棧。
userdata 在 Lua 中表示一個 C 值。 light userdata 表示一個指標。它是一個像數字一樣的值:你不需要專門建立它,它也沒有獨立的 metatable ,而且也不會被收集(因為從來不需要建立)。只要表示的 C 地址相同,兩個 light userdata 就相等。
lua_pushlstring
void lua_pushlstring (lua_State *L, const char *s, size_t len);
把指標 s
指向的長度為 len
的字串壓棧。 Lua 對這個字串做一次記憶體拷貝(或是複用一個拷貝),因此s
處的記憶體在函式返回後,可以釋放掉或是重用於其它用途。字串內可以儲存有零字元。
lua_pushnil
void lua_pushnil (lua_State *L);
把一個 nil 壓棧。
lua_pushnumber
void lua_pushnumber (lua_State *L, lua_Number n);
把一個數字 n
壓棧。
lua_pushstring
void lua_pushstring (lua_State *L, const char *s);
把指標 s
指向的以零結尾的字串壓棧。 Lua 對這個字串做一次記憶體拷貝(或是複用一個拷貝),因此s
處的記憶體在函式返回後,可以釋放掉或是重用於其它用途。字串中不能包含有零字元;第一個碰到的零字元會認為是字串的結束。
lua_pushthread
int lua_pushthread (lua_State *L);
把 L
中提供的執行緒壓棧。如果這個執行緒是當前狀態機的主執行緒的話,返回 1 。
lua_pushvalue
void lua_pushvalue (lua_State *L, int index);
把堆疊上給定有效處索引處的元素作一個拷貝壓棧。
lua_pushvfstring
const char *lua_pushvfstring (lua_State *L,
const char *fmt,
va_list argp);
等價於 lua_pushfstring
,不過是用 va_list
接收引數,而不是用可變數量的實際引數。
lua_rawequal
int lua_rawequal (lua_State *L, int index1, int index2);
如果兩個索引 index1
和 index2
處的值簡單地相等(不呼叫元方法)則返回 1 。否則返回 0 。如果任何一個索引無效也返回 0 。
lua_rawget
void lua_rawget (lua_State *L, int index);
類似於 lua_gettable
,但是作一次直接訪問(不觸發元方法)。
lua_rawgeti
void lua_rawgeti (lua_State *L, int index, int n);
把 t[n]
的值壓棧,這裡的 t
是指給定索引 index
處的一個值。這是一個直接訪問;就是說,它不會觸發元方法。
lua_rawset
void lua_rawset (lua_State *L, int index);
類似於 lua_settable
,但是是作一個直接賦值(不觸發元方法)。
lua_rawseti
void lua_rawseti (lua_State *L, int index, int n);
等價於 t[n] = v
,這裡的 t
是指給定索引 index
處的一個值,而 v
是棧頂的值。
函式將把這個值彈出棧。賦值操作是直接的;就是說,不會觸發元方法。
lua_Reader
typedef const char * (*lua_Reader) (lua_State *L,
void *data,
size_t *size);
lua_load
用到的讀取器函式,每次它需要一塊新的
chunk 的時候,lua_load
就呼叫讀取器,每次都會傳入一個引數data
。讀取器需要返回含有新的
chunk 的一塊記憶體的指標,並把 size
設為這塊記憶體的大小。記憶體塊必須在下一次函式被呼叫之前一直存在。讀取器可以通過返回一個NULL
來指示 chunk 結束。讀取器可能返回多個塊,每個塊可以有任意的大於零的尺寸。
lua_register
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
void lua_remove (lua_State *L, int index);
從給定有效索引處移除一個元素,把這個索引之上的所有元素移下來填補上這個空隙。不能用偽索引來呼叫這個函式,因為偽索引並不指向真實的棧上的位置。
lua_replace
void lua_replace (lua_State *L, int index);
把棧頂元素移動到給定位置(並且把這個棧頂元素彈出),不移動任何元素(因此在那個位置處的值被覆蓋掉)。
lua_resume
int lua_resume (lua_State *L, int narg);
在給定執行緒中啟動或繼續一個 coroutine 。
要啟動一個 coroutine 的話,首先你要建立一個新執行緒(參見lua_newthread
);然後把主函式和若干引數壓到新執行緒的堆疊上;最後呼叫lua_resume
,把narg
設為引數的個數。這次呼叫會在
coroutine 掛起時或是結束執行後返回。當函式返回時,堆疊中會有傳給 lua_yield
的所有值,或是主函式的所有返回值。如果
coroutine 切換時,lua_resume
返回LUA_YIELD
,而當
coroutine 結束執行且沒有任何錯誤時,返回 0 。如果有錯則返回錯誤程式碼(參見lua_pcall
)。在發生錯誤的情況下,堆疊沒有展開,因此你可以使用
debug API 來處理它。出錯資訊放在棧頂。要繼續執行一個 coroutine 的話,你把需要傳給yield
作結果的返回值壓入堆疊,然後呼叫lua_resume
。
lua_setallocf
void lua_setallocf (lua_State *L, lua_Alloc f, void *ud);
把指定狀態機的分配器函式換成帶上指標 ud
的f
。
lua_setfenv
int lua_setfenv (lua_State *L, int index);
從堆疊上彈出一個 table 並把它設為指定索引處值的新環境。如果指定索引處的值即不是函式又不是執行緒或是 userdata ,lua_setfenv
會返回
0 ,否則返回 1 。
lua_setfield
void lua_setfield (lua_State *L, int index, const char *k);
做一個等價於 t[k] = v
的操作,這裡t
是給出的有效索引 index
處的值,而 v
是棧頂的那個值。
這個函式將把這個值彈出堆疊。跟在 Lua 中一樣,這個函式可能觸發一個 "newindex" 事件的元方法(參見§2.8)。
lua_setglobal
void lua_setglobal (lua_State *L, const char *name);
從堆疊上彈出一個值,並將其設到全域性變數 name
中。它由一個巨集定義出來:
#define lua_setglobal(L,s) lua_setfield(L, LUA_GLOBALSINDEX, s)
lua_setmetatable
int lua_setmetatable (lua_State *L, int index);
把一個 table 彈出堆疊,並將其設為給定索引處的值的 metatable 。
lua_settable
void lua_settable (lua_State *L, int index);
作一個等價於 t[k] = v
的操作,這裡t
是一個給定有效索引 index
處的值, v
指棧頂的值,而 k
是棧頂之下的那個值。
這個函式會把鍵和值都從堆疊中彈出。和在 Lua 中一樣,這個函式可能觸發 "newindex" 事件的元方法(參見§2.8)。
就是把表在lua堆疊中的值彈出來,index 是table 在堆疊中的位置,假如 table 在 -3, 則key 應該是 -2,value 是 -1
相當於 table[key] = value.
例如:
lua_getglobal(State,"g_Userinfo");//g_Userinfo為表 -3
lua_pushstring(State,"age");//age為表中一項 -2
lua_pushnumber(State,28);//值 -1
lua_settable(State,-3);
lua_settop
void lua_settop (lua_State *L, int index);
引數允許傳入任何可接受的索引以及 0 。它將把堆疊的棧頂設為這個索引。如果新的棧頂比原來的大,超出部分的新元素將被填為nil 。如果 index
為 0 ,把棧上所有元素移除。
lua_State
typedef struct lua_State lua_State;
一個不透明的結構,它儲存了整個 Lua 直譯器的狀態。 Lua 庫是完全可重入的:它沒有任何全域性變數。(譯註:從 C 語法上來說,也不盡然。例如,在 table 的實現中用了一個靜態全域性變數 dummynode_ ,但這在正確使用時並不影響可重入性。只是萬一你錯誤連結了 lua 庫,不小心在同一程式空間中存在兩份 lua 庫實現的程式碼的話,多份 dummynode_ 不同的地址會導致一些問題。)所有的資訊都儲存在這個結構中。
這個狀態機的指標必須作為第一個引數傳遞給每一個庫函式。 lua_newstate
是一個例外,這個函式會從頭建立一個
Lua 狀態機。
lua_status
int lua_status (lua_State *L);
返回執行緒 L
的狀態。
正常的執行緒狀態是 0 。當執行緒執行完畢或發生一個錯誤時,狀態值是錯誤碼。如果執行緒被掛起,狀態為LUA_YIELD
。
lua_toboolean
int lua_toboolean (lua_State *L, int index);
把指定的索引處的的 Lua 值轉換為一個 C 中的 boolean 值( 0 或是 1 )。和 Lua 中做的所有測試一樣,lua_toboolean
會把任何不同於false 和 nil 的值當作
1 返回;否則就返回 0 。如果用一個無效索引去呼叫也會返回 0 。(如果你想只接收真正的 boolean 值,就需要使用lua_isboolean
來測試值的型別。)
lua_tocfunction
lua_CFunction lua_tocfunction (lua_State *L, int index);
把給定索引處的 Lua 值轉換為一個 C 函式。這個值必須是一個 C 函式;如果不是就返回NULL
。
lua_tointeger
lua_Integer lua_tointeger (lua_State *L, int idx);
把給定索引處的 Lua 值轉換為 lua_Integer
這樣一個有符號整數型別。這個
Lua 值必須是一個數字或是一個可以轉換為數字的字串(參見§2.2.1);否則,lua_tointeger
返回
0 。
如果數字不是一個整數,截斷小數部分的方式沒有被明確定義。
lua_tolstring
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_tolstring
返回
Lua 狀態機中字串的以對齊指標。這個字串總能保證 ( C 要求的)最後一個字元為零 ('\0
') ,而且它允許在字串內包含多個這樣的零。因為 Lua 中可能發生垃圾收集,所以不保證lua_tolstring
返回的指標,在對應的值從堆疊中移除後依然有效。
lua_tonumber
lua_Number lua_tonumber (lua_State *L, int index);
把給定索引處的 Lua 值轉換為 lua_Number
這樣一個
C 型別(參見 lua_Number
)。這個 Lua 值必須是一個數字或是一個可轉換為數字的字串(參見§2.2.1 );否則,lua_tonumber
返回
0 。
lua_topointer
const void *lua_topointer (lua_State *L, int index);
把給定索引處的值轉換為一般的 C 指標 (void*
) 。這個值可以是一個 userdata ,table ,thread 或是一個 function ;否則,lua_topointer
返回 NULL
。不同的物件有不同的指標。不存在把指標再轉回原有型別的方法。
這個函式通常只為產生 debug 資訊用。
lua_tostring
const char *lua_tostring (lua_State *L, int index);
等價於 lua_tolstring
,而引數 len
設為NULL
。
lua_tothread
lua_State *lua_tothread (lua_State *L, int index);
把給定索引處的值轉換為一個 Lua 執行緒(由 lua_State*
代表)。這個值必須是一個執行緒;否則函式返回NULL
。
lua_touserdata
void *lua_touserdata (lua_State *L, int index);
如果給定索引處的值是一個完整的 userdata ,函式返回記憶體塊的地址。如果值是一個 light userdata ,那麼就返回它表示的指標。否則,返回NULL
。
lua_type
int lua_type (lua_State *L, int index);
返回給定索引處的值的型別,當索引無效時則返回 LUA_TNONE
(那是指一個指向堆疊上的空位置的索引)。lua_type
返回的型別是一些個在lua.h
中定義的常量: LUA_TNIL
, LUA_TNUMBER
, LUA_TBOOLEAN
,LUA_TSTRING
, LUA_TTABLE
, LUA_TFUNCTION
, LUA_TUSERDATA
, LUA_TTHREAD
, LUA_TLIGHTUSERDATA
。
lua_typename
const char *lua_typename (lua_State *L, int tp);
返回 tp
表示的型別名,這個 tp
必須是 lua_type
可能返回的值中之一。
lua_Writer
typedef int (*lua_Writer) (lua_State *L,
const void* p,
size_t sz,
void* ud);
由 lua_dump
用到的寫入器函式。每次 lua_dump
產生了一塊新的
chunk ,它都會呼叫寫入器。傳入要寫入的快取 (p
) 和它的尺寸 (sz
) ,還有lua_dump
的引數data
。
寫入器會返回一個錯誤碼: 0 表示沒有錯誤;別的值均表示一個錯誤,並且會讓lua_dump
停止再次呼叫寫入器。
lua_xmove
void lua_xmove (lua_State *from, lua_State *to, int n);
傳遞 同一個 全域性狀態機下不同執行緒中的值。
這個函式會從 from
的堆疊中彈出 n
個值,然後把它們壓入 to
的堆疊中。
lua_yield
int lua_yield (lua_State *L, int nresults);
切出一個 coroutine 。
這個函式只能在一個 C 函式的返回表示式中呼叫。如下:
return lua_yield (L, nresults);
當一個 C 函式這樣呼叫 lua_yield
,正在執行中的
coroutine 將從執行中掛起,然後啟動這個 coroutine 用的那次對lua_resume
的呼叫就返回了。引數nresults
指的是堆疊中需要返回的結果個數,這些返回值將被傳遞給 lua_resume
。
3.8 - 除錯介面
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 nups; /* (u) upvalue 個數 */
int linedefined; /* (S) */
int lastlinedefined; /* (S) */
char short_src[LUA_IDSIZE]; /* (S) */
/* 私有部分 */
其它域
} lua_Debug;
一個用來攜帶活動中函式的各種資訊的結構。 lua_getstack
僅填寫這個結構中的私有部分,這些部分以後會用到。呼叫lua_getinfo
則可以填上lua_Debug
中有用資訊的那些域。
lua_Debug
中的各個域有下列含義:
source
: 如果函式是定義在一個字串中,source
就是這個字串。如果函式定義在一個檔案中,source
是一個以 '@
' 開頭的檔名。short_src
: 一個“可列印版本”的source
,用於出錯資訊。linedefined
: 函式定義開始處的行號。lastlinedefined
: 函式定義結束處的行號。what
: 如果函式是一個 Lua 函式,則為一個字串"Lua"
;如果是一個 C 函式,則為"C"
;如果它是一個 chunk 的主體部分,則為"main"
;如果是一個作了尾呼叫的函式,則為"tail"
。別的情況下,Lua 沒有關於函式的別的資訊。currentline
: 給定函式正在執行的那一行。當提供不了行號資訊的時候,currentline
被設為 -1 。name
: 給定函式的一個合理的名字。因為 Lua 中的函式也是一個值,所以它們沒有固定的名字:一些函式可能是全域性複合變數的值,另一些可能僅僅只是被儲存在一個 table 中。lua_getinfo
函式會檢查函式是這樣被呼叫的,以此來找到一個適合的名字。如果它找不到名字,name
就被設定為NULL
。namewhat
: 結實name
域。namewhat
的值可以是"global"
,"local"
,"method"
,"field"
,"upvalue"
, 或是""
(空串)。這取決於函式怎樣被呼叫。(Lua 用空串表示其它選項都不符合)nups
: 函式的 upvalue 的個數。
lua_gethook
lua_Hook lua_gethook (lua_State *L);
返回當前的鉤子函式。
lua_gethookcount
int lua_gethookcount (lua_State *L);
返回當前鉤子記數。
lua_gethookmask
int lua_gethookmask (lua_State *L);
返回當前的鉤子掩碼 (mask) 。
lua_getinfo
int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar);
返回一個指定的函式或函式呼叫的資訊。
當用於取得一次函式呼叫的資訊時,引數 ar
必須是一個有效的活動的記錄。這條記錄可以是前一次呼叫lua_getstack
得到的,或是一個鉤子
(參見lua_Hook
)得到的引數。
用於獲取一個函式的資訊時,可以把這個函式壓入堆疊,然後把 what
字串以字元 '>
' 起頭。(這個情況下,lua_getinfo
從棧頂上彈出函式。) 例如,想知道函式f
在哪一行定義的,你可以下下列程式碼:
lua_Debug ar;
lua_getfield(L, LUA_GLOBALSINDEX, "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
域; - '
u
': 填充nups
域; - '
f
': 把正在執行中指定級別處函式壓入堆疊;(譯註:一般用於獲取函式呼叫中的資訊,級別是由 ar 中的私有部分來提供。如果用於獲取靜態函式,那麼就直接把指定函式重新壓回堆疊,但這樣做通常無甚意義。) - '
L
': 壓一個 table 入棧,這個 table 中的整數索引用於描述函式中哪些行是有效行。(有效行指有實際程式碼的行,即你可以置入斷點的行。無效行包括空行和只有註釋的行。)
這個函式出錯會返回 0 (例如,what
中有一個無效選項)。
lua_getlocal
const char *lua_getlocal (lua_State *L, lua_Debug *ar, int n);
從給定活動記錄中獲取一個區域性變數的資訊。引數 ar
必須是一個有效的活動的記錄。這條記錄可以是前一次呼叫lua_getstack
得到的,或是一個鉤子
(參見lua_Hook
)得到的引數。索引n
用於選擇要檢閱哪個區域性變數( 1 表示第一個引數或是啟用的第一個區域性變數,以此類推,直到最後一個區域性變數)。 lua_getlocal
把變數的值壓入堆疊並返回它的名字。
以 '(' (正小括號)開始的變數指內部變數(迴圈控制變數,臨時變數,C 函式區域性變數)。
當索引大於區域性變數的個數時,返回 NULL
(什麼也不壓入)。
lua_getstack
int lua_getstack (lua_State *L, int level, lua_Debug *ar);
獲取直譯器的執行時棧的資訊。
這個函式用正在執行中的給定級別處的函式的活動記錄來填寫 lua_Debug
結構的一部分。
0 級表示當前執行的函式,而 n+1 級處的函式就是呼叫第 n 級函式的那一個。如果沒有錯誤,lua_getstack
返回
1 ;當呼叫傳入的級別大於堆疊深度的時候,返回 0 。
lua_getupvalue
const char *lua_getupvalue (lua_State *L, int funcindex, int n);
獲取一個 closure 的 upvalue 資訊。(對於 Lua 函式,upvalue 是函式需要使用的外部區域性變數,因此這些變數被包含在 closure 中。)lua_getupvalue
獲取第n
個
upvalue ,把這個 upvalue 的值壓入堆疊,並且返回它的名字。 funcindex
指向堆疊上 closure 的位置。( 因為 upvalue 在整個函式中都有效,所以它們沒有特別的次序。因此,它們以字母次序來編號。)
當索引號比 upvalue 數量大的時候,返回 NULL
(而且不會壓入任何東西)對於 C 函式,這個函式用空串""
表示所有 upvalue 的名字。
lua_Hook
typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar);
用於除錯的鉤子函式型別。
無論何時鉤子被呼叫,它的引數 ar
中的event
域都被設為觸發鉤子的事件。 Lua 把這些事件定義為以下常量:LUA_HOOKCALL
,LUA_HOOKRET
,LUA_HOOKTAILRET
,LUA_HOOKLINE
,
andLUA_HOOKCOUNT
。除此之外,對於 line 事件,currentline
域也被設定。要想獲得ar
中的其他域,鉤子必須呼叫 lua_getinfo
。對於返回事件,event
的正常值可能是LUA_HOOKRET
,或者是 LUA_HOOKTAILRET
。對於後一種情況,Lua
會對一個函式做的尾呼叫也模擬出一個返回事件出來;對於這個模擬的返回事件,呼叫lua_getinfo
沒有什麼作用。
當 Lua 執行在一個鉤子內部時,它將遮蔽掉其它對鉤子的呼叫。也就是說,如果一個鉤子函式內再調回 Lua 來執行一個函式或是一個 chunk ,這個執行操作不會觸發任何的鉤子。
lua_sethook
int lua_sethook (lua_State *L, lua_Hook f, int mask, int count);
設定一個除錯用鉤子函式。
引數 f
是鉤子函式。 mask
指定在哪些事件時會呼叫:它由下列一組位常量構成LUA_MASKCALL
,LUA_MASKRET
,LUA_MASKLINE
,以及LUA_MASKCOUNT
。引數count
只在
mask 中包含有LUA_MASKCOUNT
才有意義。對於每個事件,鉤子被呼叫的情況解釋如下:
- call hook: 在直譯器呼叫一個函式時被呼叫。鉤子將於 Lua 進入一個新函式後,函式獲取引數前被呼叫。
- return hook: 在直譯器從一個函式中返回時呼叫。鉤子將於 Lua 離開函式之前的那一刻被呼叫。你無權訪問被函式返回出去的那些值。(譯註:原文 (You have no access to the values to be returned by the function) 如此。但“無權訪問”一詞值得商榷。某些情況下你可以訪問到一些被命名為 (*temporary) 的區域性變數,那些索引被排在最後的 (*temporary) 變數指的就是返回值。但是由於 Lua 對特殊情況做了一些優化,比如直接返回一個被命名的區域性變數,那麼就找不到對應的 (*temporary) 變數了。本質上,返回值一定存在於此刻的區域性變數中,並且可以訪問它,只是無法確定是哪些罷了。至於這個時候函式體內的其它區域性變數,是不保證有效的。進入 return hook 的那一刻起,實際已經退出函式內部的執行環節,返回值佔用的區域性變數空間以後的部分,都有可能因 hook 本身複用它們而改變。)
- line hook: 在直譯器準備開始執行新的一行程式碼時,或是跳轉到這行程式碼中時(即使在同一行內跳轉)被呼叫。(這個事件僅僅在 Lua 執行一個 Lua 函式時發生。)
- count hook: 在直譯器每執行
count
條指令後被呼叫。(這個事件僅僅在 Lua 執行一個 Lua 函式時發生。)
鉤子可以通過設定 mask
為零遮蔽。
lua_setlocal
const char *lua_setlocal (lua_State *L, lua_Debug *ar, int n);
設定給定活動記錄中的區域性變數的值。引數 ar
與n
和 lua_getlocal
中的一樣(參見 lua_getlocal
)。lua_setlocal
把棧頂的值賦給變數然後返回變數的名字。它會將值從棧頂彈出。
當索引大於區域性變數的個數時,返回 NULL
(什麼也不彈出)。
lua_setupvalue
const char *lua_setupvalue (lua_State *L, int funcindex, int n);
設定 closure 的 upvalue 的值。它把棧頂的值彈出並賦於 upvalue 並返回 upvalue 的名字。引數funcindex
與 n
和 lua_getupvalue
中的一樣(參見 lua_getupvalue
)。
NULL
(什麼也不彈出)。
相關文章
- C++呼叫LuaC++
- Lua常用C Api介面API
- 如何呼叫api介面API
- C++呼叫C介面C++
- 實現呼叫API介面API
- Lua 和 C/C++ 互相呼叫例項分析C++
- 匯出 C/C++ API 給 Lua 使用[轉]C++API
- 呼叫api介面有什麼用?API
- lua呼叫c程式C程式
- API商品資料介面呼叫實戰API
- Cocos2d-x下Lua呼叫自定義C++類C++
- 透過例子學習Lua(7)--呼叫C/C++函式(轉)C++函式
- 淘寶API介面呼叫:案例分析與實踐API
- C++庫封裝JNI介面——實現java呼叫c++C++封裝Java
- 淘寶/天貓API分享:搜尋店鋪列表 API介面呼叫示例API
- xLua中C#呼叫LuaC#
- xLua中Lua呼叫C#C#
- C中呼叫Lua函式函式
- 淘寶API介面AG文件接入呼叫方法詳解API
- API商品資料介面呼叫爬蟲實戰API爬蟲
- 如何呼叫api介面獲取其中的資料API
- taro 介面封裝和呼叫 以豆瓣api為例封裝API
- Java爬蟲實戰:API商品資料介面呼叫Java爬蟲API
- java 呼叫百度人臉對比api介面JavaAPI
- 海外HTTP代理如何呼叫API介面提取代理IP使用?HTTPAPI
- 使用Python呼叫API介面獲取淘寶商品資料PythonAPI
- 從入門到精通:淘寶API介面呼叫全攻略API
- 淘寶API介面呼叫:案例分析與最 佳實踐(續)API
- lua——alien庫實現lua呼叫C動態連結庫(dll、so)
- 使用自定義lua解析管理器呼叫lua指令碼中的table指令碼
- 應用SWIG 封裝C++ 介面提供Java 程式呼叫封裝C++Java
- 呼叫API介面獲取淘寶商品評論:方法與實戰API
- 淘寶/天貓圖片識別商品介面 API 呼叫說明文件API
- vb呼叫winInet API介面post資料到指定的url (轉)API
- api呼叫方式API
- Nginx+lua 實現呼叫.so檔案Nginx
- toLua中Lua呼叫C#中的類C#
- app 呼叫介面APP