Lua 提供一個調(diào)試庫,這個庫中提供了創(chuàng)建自己的調(diào)試器所需的所有原語函數(shù)。雖然,Lua 沒有內(nèi)置調(diào)試器,但是開發(fā)者們?yōu)?Lua 開發(fā)了許多的開源調(diào)試器。
Lua 調(diào)試庫包括的函數(shù)如下表所示。
S.N. | 方法和描述 |
---|---|
1 | debug(): 進(jìn)入交互式調(diào)試模式,在此模式下用戶可以用其它函數(shù)查看變量的值。 |
2 | getfenv(object): 返回對象的環(huán)境。 |
3 | gethook(optional thread): 返回線程當(dāng)前的鉤子設(shè)置,總共三個值:當(dāng)前鉤子函數(shù)、當(dāng)前的鉤子掩碼與當(dāng)前的鉤子計數(shù)。 |
4 | getinfo(optional thread,function or stack leve,optional flag): 返回保存函數(shù)信息的一個表。你可以直接指定函數(shù),或者你也可以通過一個值指定函數(shù),該值為函數(shù)在當(dāng)前線程的函數(shù)調(diào)用棧的層次。其中,0 表示當(dāng)前函數(shù)(getinfo 本身);層次 1 表示調(diào)用 getinfo 的函數(shù),依次類推。如果數(shù)值大于活躍函數(shù)的總量,getinfo 則返回 nil。 |
5 | getlocal(optional thread,stack level,local index): 此函數(shù)返回在 level 層次的函數(shù)中指定索引位置處的局部變量和對應(yīng)的值。如果指定的索引處不存在局部變量,則返回 nil。當(dāng) level 超出范圍時,則拋出錯誤。 |
6 | getmetatable(value): 返回指定對象的元表,如果不存在則返回 nil。 |
7 | getregistry(): 返回寄存器表。寄存器表是一個預(yù)定義的用于 C 代碼存儲 Lua 值的表。 |
8 | getupvalue(func function,upvalue index): 根據(jù)指定索引返回函數(shù) func 的 upvalue 值(譯注:upvalue 值與函數(shù)局部變量的區(qū)別在于,即使函數(shù)并非活躍狀態(tài)也可能有 upvalue 值,而非活躍函數(shù)則不存在局部變量,所以其第一個參數(shù)不是棧的層次而是函數(shù))。如果不存在,則返回 nil。 |
9 | setfenv(function or thread or userdata,environment table): 將指定的對象的環(huán)境設(shè)置為 table,即改變對象的作用域。 |
10 | sethook(optional thread,hook function,hook mask string with "c" and/or "r" and/or "l",optional instruction count): 把指定函數(shù)設(shè)置為鉤子。字符串掩碼和計數(shù)值表示鉤子被調(diào)用的時機(jī)。這里,c 表示每次調(diào)用函數(shù)時都會執(zhí)行鉤子;r 表示每次從函數(shù)中返回時都調(diào)用鉤子;l 表示每進(jìn)入新的一行調(diào)用鉤子。 |
11 | setlocal(optional thread,stack level,local index,value): 在指定的棧深度的函數(shù)中,為 index 指定的局部變量賦予值。如果局部變量不存在,則返回 nil。若 level 超出范圍則拋出錯誤;否則返回局部變量的名稱。 |
12 | setmetatable(value,metatable): 為指定的對象設(shè)置元表,元表可以為 nil。 |
13 | setupvalue(function,upvalue index,value): 為指定函數(shù)中索引指定的 upvalue 變量賦值。如果 upvalue 不存在,則返回 nil。否則返回此 upvalue 的名稱。 |
14 | traceback(optional thread,optional meesage string,opitona level argument): 用 traceback 構(gòu)建擴(kuò)展錯誤消息。 |
上面的表中列出了 Lua 的全部調(diào)試函數(shù),我們經(jīng)常用到的調(diào)試庫都會用到上面的函數(shù),它讓調(diào)試變得非常容易。雖然提供了便捷的接口,但是想要用上面的函數(shù)創(chuàng)建一個自己的調(diào)試器并不是件容易的事。無論怎樣,我們可以看一下下面這個例子中怎么使用這些調(diào)試函數(shù)的。
function myfunction ()
print(debug.traceback("Stack trace"))
print(debug.getinfo(1))
print("Stack trace end")
return 10
end
myfunction ()
print(debug.getinfo(1))
執(zhí)行上面的程序,我們可以得到如下的棧軌跡信息:
Stack trace
stack traceback:
test2.lua:2: in function 'myfunction'
test2.lua:8: in main chunk
[C]: ?
table: 0054C6C8
Stack trace end
上面的例子中,我們使用 debug.trace 函數(shù)輸出了棧軌跡。 debug.getinfo 函數(shù)獲得函數(shù)的當(dāng)前表。
在調(diào)試過程中,我們常常需要查看或修改函數(shù)局部變量的值。因此,我們可以用 getupvalue 獲得變量的值,用 setupvalue 修改變量的值。示例如下:
function newCounter ()
local n = 0
local k = 0
return function ()
k = n
n = n + 1
return n
end
end
counter = newCounter ()
print(counter())
print(counter())
local i = 1
repeat
name, val = debug.getupvalue(counter, i)
if name then
print ("index", i, name, "=", val)
if(name == "n") then
debug.setupvalue (counter,2,10)
end
i = i + 1
end -- if
until not name
print(counter())
運(yùn)行上面的程序,我們可以得到如下面的輸出結(jié)果:
1
2
index 1 k = 1
index 2 n = 2
11
在這個例子中,每次調(diào)用 counter 都會更新該閉包函數(shù)。我們可以通過 getupvalue 查看其當(dāng)前的局部變量值。隨后,我們更新局部變量的值。在為 n 設(shè)置新值之前,其值為 2。調(diào)用 setupvalue 后,n 被設(shè)置為 10。再調(diào)用 counter 時,它就會返回值 11 而不再是 3。
命令行調(diào)試就是使用命令行命令和 print 語句來調(diào)試程序。已經(jīng)有許多現(xiàn)成的 Lua 命令行調(diào)試工具,下面列出了其中的一部分:
圖形界面的調(diào)試工具往往和集成開發(fā)環(huán)境(IDE)打包在一起。它允許在可視環(huán)境下進(jìn)行調(diào)試,比如查看變量值,棧跟蹤等。通過 IDE 的圖形界面,你可以設(shè)置斷點(diǎn)單步執(zhí)行程序。
下面列出了幾種圖形界面的調(diào)試工具。