C++呼叫Lua API介面

工程師WWW發表於2014-03-05

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_callnargs 是你壓入堆疊的引數個數。當函式呼叫完畢後,所有的引數以及函式本身都會出棧。而函式的返回值這時則被壓入堆疊。返回值的個數將被調整為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 的返回值可以是:

這個函式僅僅加栽 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_HOOKCALLLUA_HOOKRET,LUA_HOOKTAILRETLUA_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_MASKCALLLUA_MASKRETLUA_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)。

當索引大於 upvalue 的個數時,返回 NULL (什麼也不彈出)。

相關文章